mirror of
https://github.com/EduApps-CDG/OpenDX
synced 2024-12-30 09:45:37 +01:00
Version 0.53
-----BEGIN PGP SIGNATURE----- iQEzBAABCAAdFiEEJz0EC1ETuIbRoJDUyMxhNCejHJkFAlsLDL4ACgkQyMxhNCej HJmIPwgArq3gx2qLKKLokrCyVbwf5UfYtMbnyEQCs7nSBbb0JiaeQXJClAdIwFP6 VncCpCDOjvssHAiXMF1hfbHDMvVpMa3nwz+O2bOKFxg9OCt69T0wqbOvNVuJzEq4 7zXWNBXegPJaY5KQXiJORetU/xNcb8/ikWEAT57vkRu2RvvT2ct/oaynWZtgh+X5 /OMHW1nMP9Bvwm5ZCWw2fCdT9evqIrXL3IreoJKX+dW/10oIaUnh+Q5Fcm7L0s7i dYkmm1KM6WiHpO/duK0SpbOl9ASzorwtcRjgM2syzM0QljcUpdnRCDXsuVWYOpRL 7GbtyzdVC/SJknJoWMdTcpIX6fjYPA== =nkRK -----END PGP SIGNATURE----- gpgsig -----BEGIN PGP SIGNATURE----- iQEzBAABCAAdFiEEJz0EC1ETuIbRoJDUyMxhNCejHJkFAlsOvCkACgkQyMxhNCej HJlusQgAkfcCUgFLMLGoUeOJaHkpDnv5/s13AMG3a+m9SLUavQ87izysrp6cEaF6 1O1Rxf/NHqhOh8jGwHILVmDWeYzDGkNKUW0/g0A0hcLMDyh5f5zMVqYoX9ITsjmG w5Woc4I7JPqsPdqJ0FOk/dQKIrnVXr/SZXrna55ZvXPI9q1wz0QCbE4E/q47tJUA 3F5yw+eNaRWEHe7T9wSXdtuVo7R1NFqewt5kTvgiYg6HCWSCNAvgTVHnEg2tpaNC rzipvxXKSNbDB30JpC8+R6aP4b7z6P9p1KjyoSKT7Jb5kvOw3p6eY5WQq69KUhhq EjTMwUrFaP1K6IJwgWfxLxIufp5pqw== =JJRk -----END PGP SIGNATURE----- Merge tag 'v0.53' into openvr-v2 Version 0.53
This commit is contained in:
commit
7fe4a70342
@ -6,6 +6,8 @@ For the current status of the project, please refer to the [project wiki](https:
|
|||||||
|
|
||||||
For binary releases, see the [releases](https://github.com/doitsujin/dxvk/releases) page.
|
For binary releases, see the [releases](https://github.com/doitsujin/dxvk/releases) page.
|
||||||
|
|
||||||
|
For Direct3D 10 support, check out [DXUP](https://github.com/Joshua-Ashton/dxup), which can be used together with DXVK.
|
||||||
|
|
||||||
## Build instructions
|
## Build instructions
|
||||||
|
|
||||||
### Requirements:
|
### Requirements:
|
||||||
|
@ -856,9 +856,7 @@ namespace dxvk {
|
|||||||
if (view->GetResourceType() != D3D11_RESOURCE_DIMENSION_BUFFER) {
|
if (view->GetResourceType() != D3D11_RESOURCE_DIMENSION_BUFFER) {
|
||||||
EmitCs([cDstImageView = view->GetImageView()]
|
EmitCs([cDstImageView = view->GetImageView()]
|
||||||
(DxvkContext* ctx) {
|
(DxvkContext* ctx) {
|
||||||
ctx->generateMipmaps(
|
ctx->generateMipmaps(cDstImageView);
|
||||||
cDstImageView->image(),
|
|
||||||
cDstImageView->subresources());
|
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
Logger::err("D3D11: GenerateMips called on a buffer");
|
Logger::err("D3D11: GenerateMips called on a buffer");
|
||||||
@ -1237,8 +1235,18 @@ namespace dxvk {
|
|||||||
auto inputLayout = static_cast<D3D11InputLayout*>(pInputLayout);
|
auto inputLayout = static_cast<D3D11InputLayout*>(pInputLayout);
|
||||||
|
|
||||||
if (m_state.ia.inputLayout != inputLayout) {
|
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;
|
m_state.ia.inputLayout = inputLayout;
|
||||||
ApplyInputLayout();
|
|
||||||
|
if (!equal)
|
||||||
|
ApplyInputLayout();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2290,8 +2298,11 @@ namespace dxvk {
|
|||||||
const D3D11_RECT* pRects) {
|
const D3D11_RECT* pRects) {
|
||||||
m_state.rs.numScissors = NumRects;
|
m_state.rs.numScissors = NumRects;
|
||||||
|
|
||||||
for (uint32_t i = 0; i < NumRects; i++)
|
for (uint32_t i = 0; i < NumRects; i++) {
|
||||||
m_state.rs.scissors.at(i) = pRects[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) {
|
if (m_state.rs.state != nullptr) {
|
||||||
D3D11_RASTERIZER_DESC rsDesc;
|
D3D11_RASTERIZER_DESC rsDesc;
|
||||||
@ -2554,17 +2565,22 @@ namespace dxvk {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (uint32_t i = 0; i < m_state.rs.numViewports; i++) {
|
for (uint32_t i = 0; i < m_state.rs.numViewports; i++) {
|
||||||
// TODO D3D11 docs aren't clear about what should happen
|
|
||||||
// when there are undefined scissor rects for a viewport.
|
|
||||||
// Figure out what it does on Windows.
|
|
||||||
if (enableScissorTest && (i < m_state.rs.numScissors)) {
|
if (enableScissorTest && (i < m_state.rs.numScissors)) {
|
||||||
const D3D11_RECT& sr = m_state.rs.scissors.at(i);
|
D3D11_RECT sr = m_state.rs.scissors.at(i);
|
||||||
|
|
||||||
scissors.at(i) = VkRect2D {
|
VkOffset2D srPosA;
|
||||||
VkOffset2D { sr.left, sr.top },
|
srPosA.x = std::max<int32_t>(0, sr.left);
|
||||||
VkExtent2D {
|
srPosA.y = std::max<int32_t>(0, sr.top);
|
||||||
static_cast<uint32_t>(sr.right - sr.left),
|
|
||||||
static_cast<uint32_t>(sr.bottom - 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 {
|
} else {
|
||||||
scissors.at(i) = VkRect2D {
|
scissors.at(i) = VkRect2D {
|
||||||
VkOffset2D { 0, 0 },
|
VkOffset2D { 0, 0 },
|
||||||
|
@ -92,7 +92,7 @@ namespace dxvk {
|
|||||||
m_mappedResources.push_back(entry);
|
m_mappedResources.push_back(entry);
|
||||||
|
|
||||||
// Fill mapped resource structure
|
// Fill mapped resource structure
|
||||||
pMappedResource->pData = entry.DataSlice.ptr();
|
pMappedResource->pData = entry.MapPointer;
|
||||||
pMappedResource->RowPitch = entry.RowPitch;
|
pMappedResource->RowPitch = entry.RowPitch;
|
||||||
pMappedResource->DepthPitch = entry.DepthPitch;
|
pMappedResource->DepthPitch = entry.DepthPitch;
|
||||||
return S_OK;
|
return S_OK;
|
||||||
@ -107,7 +107,7 @@ namespace dxvk {
|
|||||||
// Return same memory region as earlier
|
// Return same memory region as earlier
|
||||||
entry->MapType = D3D11_MAP_WRITE_NO_OVERWRITE;
|
entry->MapType = D3D11_MAP_WRITE_NO_OVERWRITE;
|
||||||
|
|
||||||
pMappedResource->pData = entry->DataSlice.ptr();
|
pMappedResource->pData = entry->MapPointer;
|
||||||
pMappedResource->RowPitch = entry->RowPitch;
|
pMappedResource->RowPitch = entry->RowPitch;
|
||||||
pMappedResource->DepthPitch = entry->DepthPitch;
|
pMappedResource->DepthPitch = entry->DepthPitch;
|
||||||
return S_OK;
|
return S_OK;
|
||||||
@ -145,9 +145,12 @@ namespace dxvk {
|
|||||||
D3D11_MAP MapType,
|
D3D11_MAP MapType,
|
||||||
UINT MapFlags,
|
UINT MapFlags,
|
||||||
D3D11DeferredContextMapEntry* pMapEntry) {
|
D3D11DeferredContextMapEntry* pMapEntry) {
|
||||||
const D3D11Buffer* pBuffer = static_cast<D3D11Buffer*>(pResource);
|
D3D11Buffer* pBuffer = static_cast<D3D11Buffer*>(pResource);
|
||||||
const Rc<DxvkBuffer> buffer = pBuffer->GetBuffer();
|
const Rc<DxvkBuffer> buffer = pBuffer->GetBuffer();
|
||||||
|
|
||||||
|
D3D11_BUFFER_DESC bufferDesc;
|
||||||
|
pBuffer->GetDesc(&bufferDesc);
|
||||||
|
|
||||||
if (!(buffer->memFlags() & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)) {
|
if (!(buffer->memFlags() & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)) {
|
||||||
Logger::err("D3D11: Cannot map a device-local buffer");
|
Logger::err("D3D11: Cannot map a device-local buffer");
|
||||||
return E_INVALIDARG;
|
return E_INVALIDARG;
|
||||||
@ -158,7 +161,20 @@ namespace dxvk {
|
|||||||
pMapEntry->MapType = D3D11_MAP_WRITE_DISCARD;
|
pMapEntry->MapType = D3D11_MAP_WRITE_DISCARD;
|
||||||
pMapEntry->RowPitch = pBuffer->GetSize();
|
pMapEntry->RowPitch = pBuffer->GetSize();
|
||||||
pMapEntry->DepthPitch = pBuffer->GetSize();
|
pMapEntry->DepthPitch = pBuffer->GetSize();
|
||||||
pMapEntry->DataSlice = AllocUpdateBufferSlice(pBuffer->GetSize());
|
|
||||||
|
if (bufferDesc.Usage == D3D11_USAGE_DYNAMIC) {
|
||||||
|
// For resources that cannot be written by the GPU,
|
||||||
|
// we may write to the buffer resource directly and
|
||||||
|
// just swap in the physical buffer slice as needed.
|
||||||
|
pMapEntry->BufferSlice = buffer->allocPhysicalSlice();
|
||||||
|
pMapEntry->MapPointer = pMapEntry->BufferSlice.mapPtr(0);
|
||||||
|
} else {
|
||||||
|
// For GPU-writable resources, we need a data slice
|
||||||
|
// to perform the update operation at execution time.
|
||||||
|
pMapEntry->DataSlice = AllocUpdateBufferSlice(pBuffer->GetSize());
|
||||||
|
pMapEntry->MapPointer = pMapEntry->DataSlice.ptr();
|
||||||
|
}
|
||||||
|
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -203,6 +219,7 @@ namespace dxvk {
|
|||||||
pMapEntry->RowPitch = xSize;
|
pMapEntry->RowPitch = xSize;
|
||||||
pMapEntry->DepthPitch = ySize;
|
pMapEntry->DepthPitch = ySize;
|
||||||
pMapEntry->DataSlice = AllocUpdateBufferSlice(zSize);
|
pMapEntry->DataSlice = AllocUpdateBufferSlice(zSize);
|
||||||
|
pMapEntry->MapPointer = pMapEntry->DataSlice.ptr();
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -212,14 +229,26 @@ namespace dxvk {
|
|||||||
const D3D11DeferredContextMapEntry* pMapEntry) {
|
const D3D11DeferredContextMapEntry* pMapEntry) {
|
||||||
D3D11Buffer* pBuffer = static_cast<D3D11Buffer*>(pResource);
|
D3D11Buffer* pBuffer = static_cast<D3D11Buffer*>(pResource);
|
||||||
|
|
||||||
EmitCs([
|
D3D11_BUFFER_DESC bufferDesc;
|
||||||
cDstBuffer = pBuffer->GetBuffer(),
|
pBuffer->GetDesc(&bufferDesc);
|
||||||
cDataSlice = pMapEntry->DataSlice
|
|
||||||
] (DxvkContext* ctx) {
|
if (bufferDesc.Usage == D3D11_USAGE_DYNAMIC) {
|
||||||
DxvkPhysicalBufferSlice slice = cDstBuffer->allocPhysicalSlice();
|
EmitCs([
|
||||||
std::memcpy(slice.mapPtr(0), cDataSlice.ptr(), cDataSlice.length());
|
cDstBuffer = pBuffer->GetBuffer(),
|
||||||
ctx->invalidateBuffer(cDstBuffer, slice);
|
cPhysSlice = pMapEntry->BufferSlice
|
||||||
});
|
] (DxvkContext* ctx) {
|
||||||
|
ctx->invalidateBuffer(cDstBuffer, cPhysSlice);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
EmitCs([
|
||||||
|
cDstBuffer = pBuffer->GetBuffer(),
|
||||||
|
cDataSlice = pMapEntry->DataSlice
|
||||||
|
] (DxvkContext* ctx) {
|
||||||
|
DxvkPhysicalBufferSlice slice = cDstBuffer->allocPhysicalSlice();
|
||||||
|
std::memcpy(slice.mapPtr(0), cDataSlice.ptr(), cDataSlice.length());
|
||||||
|
ctx->invalidateBuffer(cDstBuffer, slice);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -11,12 +11,14 @@
|
|||||||
namespace dxvk {
|
namespace dxvk {
|
||||||
|
|
||||||
struct D3D11DeferredContextMapEntry {
|
struct D3D11DeferredContextMapEntry {
|
||||||
Com<ID3D11Resource> pResource;
|
Com<ID3D11Resource> pResource;
|
||||||
UINT Subresource;
|
UINT Subresource;
|
||||||
D3D11_MAP MapType;
|
D3D11_MAP MapType;
|
||||||
UINT RowPitch;
|
UINT RowPitch;
|
||||||
UINT DepthPitch;
|
UINT DepthPitch;
|
||||||
DxvkDataSlice DataSlice;
|
DxvkDataSlice DataSlice;
|
||||||
|
DxvkPhysicalBufferSlice BufferSlice;
|
||||||
|
void* MapPointer;
|
||||||
};
|
};
|
||||||
|
|
||||||
class D3D11DeferredContext : public D3D11DeviceContext {
|
class D3D11DeferredContext : public D3D11DeviceContext {
|
||||||
|
@ -182,7 +182,7 @@ namespace dxvk {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const Com<D3D11Texture1D> texture = new D3D11Texture1D(this, &desc);
|
const Com<D3D11Texture1D> texture = new D3D11Texture1D(this, &desc);
|
||||||
this->InitTexture(texture->GetCommonTexture()->GetImage(), pInitialData);
|
this->InitTexture(texture->GetCommonTexture(), pInitialData);
|
||||||
*ppTexture1D = texture.ref();
|
*ppTexture1D = texture.ref();
|
||||||
return S_OK;
|
return S_OK;
|
||||||
} catch (const DxvkError& e) {
|
} catch (const DxvkError& e) {
|
||||||
@ -219,7 +219,7 @@ namespace dxvk {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const Com<D3D11Texture2D> texture = new D3D11Texture2D(this, &desc);
|
const Com<D3D11Texture2D> texture = new D3D11Texture2D(this, &desc);
|
||||||
this->InitTexture(texture->GetCommonTexture()->GetImage(), pInitialData);
|
this->InitTexture(texture->GetCommonTexture(), pInitialData);
|
||||||
*ppTexture2D = texture.ref();
|
*ppTexture2D = texture.ref();
|
||||||
return S_OK;
|
return S_OK;
|
||||||
} catch (const DxvkError& e) {
|
} catch (const DxvkError& e) {
|
||||||
@ -256,7 +256,7 @@ namespace dxvk {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const Com<D3D11Texture3D> texture = new D3D11Texture3D(this, &desc);
|
const Com<D3D11Texture3D> texture = new D3D11Texture3D(this, &desc);
|
||||||
this->InitTexture(texture->GetCommonTexture()->GetImage(), pInitialData);
|
this->InitTexture(texture->GetCommonTexture(), pInitialData);
|
||||||
*ppTexture3D = texture.ref();
|
*ppTexture3D = texture.ref();
|
||||||
return S_OK;
|
return S_OK;
|
||||||
} catch (const DxvkError& e) {
|
} catch (const DxvkError& e) {
|
||||||
@ -413,9 +413,6 @@ namespace dxvk {
|
|||||||
viewInfo.numLevels = desc.Texture2D.MipLevels;
|
viewInfo.numLevels = desc.Texture2D.MipLevels;
|
||||||
viewInfo.minLayer = 0;
|
viewInfo.minLayer = 0;
|
||||||
viewInfo.numLayers = 1;
|
viewInfo.numLayers = 1;
|
||||||
|
|
||||||
if (m_dxbcOptions.test(DxbcOption::ForceTex2DArray))
|
|
||||||
viewInfo.type = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case D3D11_SRV_DIMENSION_TEXTURE2DARRAY:
|
case D3D11_SRV_DIMENSION_TEXTURE2DARRAY:
|
||||||
@ -432,9 +429,6 @@ namespace dxvk {
|
|||||||
viewInfo.numLevels = 1;
|
viewInfo.numLevels = 1;
|
||||||
viewInfo.minLayer = 0;
|
viewInfo.minLayer = 0;
|
||||||
viewInfo.numLayers = 1;
|
viewInfo.numLayers = 1;
|
||||||
|
|
||||||
if (m_dxbcOptions.test(DxbcOption::ForceTex2DArray))
|
|
||||||
viewInfo.type = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case D3D11_SRV_DIMENSION_TEXTURE2DMSARRAY:
|
case D3D11_SRV_DIMENSION_TEXTURE2DMSARRAY:
|
||||||
@ -624,9 +618,6 @@ namespace dxvk {
|
|||||||
viewInfo.numLevels = 1;
|
viewInfo.numLevels = 1;
|
||||||
viewInfo.minLayer = 0;
|
viewInfo.minLayer = 0;
|
||||||
viewInfo.numLayers = 1;
|
viewInfo.numLayers = 1;
|
||||||
|
|
||||||
if (m_dxbcOptions.test(DxbcOption::ForceTex2DArray))
|
|
||||||
viewInfo.type = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case D3D11_UAV_DIMENSION_TEXTURE2DARRAY:
|
case D3D11_UAV_DIMENSION_TEXTURE2DARRAY:
|
||||||
@ -1124,7 +1115,10 @@ namespace dxvk {
|
|||||||
ID3D11GeometryShader** ppGeometryShader) {
|
ID3D11GeometryShader** ppGeometryShader) {
|
||||||
InitReturnPtr(ppGeometryShader);
|
InitReturnPtr(ppGeometryShader);
|
||||||
Logger::err("D3D11Device::CreateGeometryShaderWithStreamOutput: Not implemented");
|
Logger::err("D3D11Device::CreateGeometryShaderWithStreamOutput: Not implemented");
|
||||||
return E_NOTIMPL;
|
|
||||||
|
// Returning S_OK instead of an error fixes some issues
|
||||||
|
// with Overwatch until this is properly implemented
|
||||||
|
return m_d3d11Options.test(D3D11Option::FakeStreamOutSupport) ? S_OK : E_NOTIMPL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1813,6 +1807,8 @@ namespace dxvk {
|
|||||||
enabled.shaderFloat64 = supported.shaderFloat64;
|
enabled.shaderFloat64 = supported.shaderFloat64;
|
||||||
enabled.shaderInt64 = supported.shaderInt64;
|
enabled.shaderInt64 = supported.shaderInt64;
|
||||||
enabled.tessellationShader = VK_TRUE;
|
enabled.tessellationShader = VK_TRUE;
|
||||||
|
// TODO enable unconditionally once RADV gains support
|
||||||
|
enabled.shaderStorageImageMultisample = supported.shaderStorageImageMultisample;
|
||||||
enabled.shaderStorageImageReadWithoutFormat = supported.shaderStorageImageReadWithoutFormat;
|
enabled.shaderStorageImageReadWithoutFormat = supported.shaderStorageImageReadWithoutFormat;
|
||||||
enabled.shaderStorageImageWriteWithoutFormat = VK_TRUE;
|
enabled.shaderStorageImageWriteWithoutFormat = VK_TRUE;
|
||||||
}
|
}
|
||||||
@ -1849,8 +1845,10 @@ namespace dxvk {
|
|||||||
void D3D11Device::InitBuffer(
|
void D3D11Device::InitBuffer(
|
||||||
D3D11Buffer* pBuffer,
|
D3D11Buffer* pBuffer,
|
||||||
const D3D11_SUBRESOURCE_DATA* pInitialData) {
|
const D3D11_SUBRESOURCE_DATA* pInitialData) {
|
||||||
const DxvkBufferSlice bufferSlice
|
const DxvkBufferSlice bufferSlice = pBuffer->GetBufferSlice();
|
||||||
= pBuffer->GetBufferSlice();
|
|
||||||
|
D3D11_BUFFER_DESC desc;
|
||||||
|
pBuffer->GetDesc(&desc);
|
||||||
|
|
||||||
if (pInitialData != nullptr && pInitialData->pSysMem != nullptr) {
|
if (pInitialData != nullptr && pInitialData->pSysMem != nullptr) {
|
||||||
LockResourceInitContext();
|
LockResourceInitContext();
|
||||||
@ -1861,14 +1859,25 @@ namespace dxvk {
|
|||||||
bufferSlice.length(),
|
bufferSlice.length(),
|
||||||
pInitialData->pSysMem);
|
pInitialData->pSysMem);
|
||||||
|
|
||||||
|
UnlockResourceInitContext(1);
|
||||||
|
} else if (desc.Usage == D3D11_USAGE_DEFAULT) {
|
||||||
|
LockResourceInitContext();
|
||||||
|
|
||||||
|
m_resourceInitContext->clearBuffer(
|
||||||
|
bufferSlice.buffer(),
|
||||||
|
bufferSlice.offset(),
|
||||||
|
bufferSlice.length(),
|
||||||
|
0u);
|
||||||
|
|
||||||
UnlockResourceInitContext(1);
|
UnlockResourceInitContext(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void D3D11Device::InitTexture(
|
void D3D11Device::InitTexture(
|
||||||
const Rc<DxvkImage>& image,
|
D3D11CommonTexture* pTexture,
|
||||||
const D3D11_SUBRESOURCE_DATA* pInitialData) {
|
const D3D11_SUBRESOURCE_DATA* pInitialData) {
|
||||||
|
const Rc<DxvkImage> image = pTexture->GetImage();
|
||||||
const DxvkFormatInfo* formatInfo = imageFormatInfo(image->info().format);
|
const DxvkFormatInfo* formatInfo = imageFormatInfo(image->info().format);
|
||||||
|
|
||||||
if (pInitialData != nullptr && pInitialData->pSysMem != nullptr) {
|
if (pInitialData != nullptr && pInitialData->pSysMem != nullptr) {
|
||||||
|
@ -19,6 +19,7 @@ namespace dxvk {
|
|||||||
class DxgiAdapter;
|
class DxgiAdapter;
|
||||||
|
|
||||||
class D3D11Buffer;
|
class D3D11Buffer;
|
||||||
|
class D3D11CommonTexture;
|
||||||
class D3D11Counter;
|
class D3D11Counter;
|
||||||
class D3D11DeviceContext;
|
class D3D11DeviceContext;
|
||||||
class D3D11ImmediateContext;
|
class D3D11ImmediateContext;
|
||||||
@ -380,7 +381,7 @@ namespace dxvk {
|
|||||||
const D3D11_SUBRESOURCE_DATA* pInitialData);
|
const D3D11_SUBRESOURCE_DATA* pInitialData);
|
||||||
|
|
||||||
void InitTexture(
|
void InitTexture(
|
||||||
const Rc<DxvkImage>& image,
|
D3D11CommonTexture* pTexture,
|
||||||
const D3D11_SUBRESOURCE_DATA* pInitialData);
|
const D3D11_SUBRESOURCE_DATA* pInitialData);
|
||||||
|
|
||||||
HRESULT GetFormatSupportFlags(
|
HRESULT GetFormatSupportFlags(
|
||||||
|
@ -4,11 +4,11 @@
|
|||||||
namespace dxvk {
|
namespace dxvk {
|
||||||
|
|
||||||
D3D11InputLayout::D3D11InputLayout(
|
D3D11InputLayout::D3D11InputLayout(
|
||||||
D3D11Device* pDevice,
|
D3D11Device* pDevice,
|
||||||
uint32_t numAttributes,
|
uint32_t numAttributes,
|
||||||
const DxvkVertexAttribute* pAttributes,
|
const DxvkVertexAttribute* pAttributes,
|
||||||
uint32_t numBindings,
|
uint32_t numBindings,
|
||||||
const DxvkVertexBinding* pBindings)
|
const DxvkVertexBinding* pBindings)
|
||||||
: m_device(pDevice) {
|
: m_device(pDevice) {
|
||||||
m_attributes.resize(numAttributes);
|
m_attributes.resize(numAttributes);
|
||||||
m_bindings.resize(numBindings);
|
m_bindings.resize(numBindings);
|
||||||
@ -55,4 +55,25 @@ namespace dxvk {
|
|||||||
m_bindings.data());
|
m_bindings.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool D3D11InputLayout::Compare(const D3D11InputLayout* pOther) const {
|
||||||
|
bool eq = m_attributes.size() == pOther->m_attributes.size()
|
||||||
|
&& m_bindings.size() == pOther->m_bindings.size();
|
||||||
|
|
||||||
|
for (uint32_t i = 0; eq && i < m_attributes.size(); i++) {
|
||||||
|
eq &= m_attributes[i].location == pOther->m_attributes[i].location
|
||||||
|
&& m_attributes[i].binding == pOther->m_attributes[i].binding
|
||||||
|
&& m_attributes[i].format == pOther->m_attributes[i].format
|
||||||
|
&& m_attributes[i].offset == pOther->m_attributes[i].offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint32_t i = 0; eq && i < m_bindings.size(); i++) {
|
||||||
|
eq &= m_bindings[i].binding == pOther->m_bindings[i].binding
|
||||||
|
&& m_bindings[i].fetchRate == pOther->m_bindings[i].fetchRate
|
||||||
|
&& m_bindings[i].inputRate == pOther->m_bindings[i].inputRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
return eq;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -11,23 +11,26 @@ namespace dxvk {
|
|||||||
public:
|
public:
|
||||||
|
|
||||||
D3D11InputLayout(
|
D3D11InputLayout(
|
||||||
D3D11Device* pDevice,
|
D3D11Device* pDevice,
|
||||||
uint32_t numAttributes,
|
uint32_t numAttributes,
|
||||||
const DxvkVertexAttribute* pAttributes,
|
const DxvkVertexAttribute* pAttributes,
|
||||||
uint32_t numBindings,
|
uint32_t numBindings,
|
||||||
const DxvkVertexBinding* pBindings);
|
const DxvkVertexBinding* pBindings);
|
||||||
|
|
||||||
~D3D11InputLayout();
|
~D3D11InputLayout();
|
||||||
|
|
||||||
HRESULT STDMETHODCALLTYPE QueryInterface(
|
HRESULT STDMETHODCALLTYPE QueryInterface(
|
||||||
REFIID riid,
|
REFIID riid,
|
||||||
void** ppvObject) final;
|
void** ppvObject) final;
|
||||||
|
|
||||||
void STDMETHODCALLTYPE GetDevice(
|
void STDMETHODCALLTYPE GetDevice(
|
||||||
ID3D11Device **ppDevice) final;
|
ID3D11Device** ppDevice) final;
|
||||||
|
|
||||||
void BindToContext(
|
void BindToContext(
|
||||||
const Rc<DxvkContext>& ctx);
|
const Rc<DxvkContext>& ctx);
|
||||||
|
|
||||||
|
bool Compare(
|
||||||
|
const D3D11InputLayout* pOther) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
@ -5,8 +5,9 @@
|
|||||||
namespace dxvk {
|
namespace dxvk {
|
||||||
|
|
||||||
const static std::unordered_map<std::string, D3D11OptionSet> g_d3d11AppOptions = {{
|
const static std::unordered_map<std::string, D3D11OptionSet> g_d3d11AppOptions = {{
|
||||||
{ "Dishonored2.exe", D3D11OptionSet(D3D11Option::AllowMapFlagNoWait) },
|
{ "Dishonored2.exe", D3D11OptionSet(D3D11Option::AllowMapFlagNoWait) },
|
||||||
{ "Fallout4.exe", D3D11OptionSet(D3D11Option::DisableGetDataFlagDoNotFlush) },
|
{ "Fallout4.exe", D3D11OptionSet(D3D11Option::DisableGetDataFlagDoNotFlush) },
|
||||||
|
{ "Overwatch.exe", D3D11OptionSet(D3D11Option::FakeStreamOutSupport) },
|
||||||
}};
|
}};
|
||||||
|
|
||||||
|
|
||||||
|
@ -23,6 +23,16 @@ namespace dxvk {
|
|||||||
* when passing the \c DONOTFLUSH flag.
|
* when passing the \c DONOTFLUSH flag.
|
||||||
*/
|
*/
|
||||||
DisableGetDataFlagDoNotFlush = 1,
|
DisableGetDataFlagDoNotFlush = 1,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Fakes stream output support
|
||||||
|
*
|
||||||
|
* Temporary hack that fixes issues in some games
|
||||||
|
* which technically need stream output but work
|
||||||
|
* well enough without it. Will be removed once
|
||||||
|
* Stream Output is properly supported in DXVK.
|
||||||
|
*/
|
||||||
|
FakeStreamOutSupport = 63,
|
||||||
};
|
};
|
||||||
|
|
||||||
using D3D11OptionSet = Flags<D3D11Option>;
|
using D3D11OptionSet = Flags<D3D11Option>;
|
||||||
|
@ -43,15 +43,15 @@ namespace dxvk {
|
|||||||
|
|
||||||
|
|
||||||
HRESULT STDMETHODCALLTYPE D3D11Presenter::CreateSwapChainBackBuffer(
|
HRESULT STDMETHODCALLTYPE D3D11Presenter::CreateSwapChainBackBuffer(
|
||||||
const DXGI_SWAP_CHAIN_DESC* pSwapChainDesc,
|
const DXGI_SWAP_CHAIN_DESC1* pSwapChainDesc,
|
||||||
IDXGIVkBackBuffer** ppInterface) {
|
IDXGIVkBackBuffer** ppInterface) {
|
||||||
D3D11_COMMON_TEXTURE_DESC desc;
|
D3D11_COMMON_TEXTURE_DESC desc;
|
||||||
desc.Width = pSwapChainDesc->BufferDesc.Width;
|
desc.Width = pSwapChainDesc->Width;
|
||||||
desc.Height = pSwapChainDesc->BufferDesc.Height;
|
desc.Height = pSwapChainDesc->Height;
|
||||||
desc.Depth = 1;
|
desc.Depth = 1;
|
||||||
desc.MipLevels = 1;
|
desc.MipLevels = 1;
|
||||||
desc.ArraySize = 1;
|
desc.ArraySize = 1;
|
||||||
desc.Format = pSwapChainDesc->BufferDesc.Format;
|
desc.Format = pSwapChainDesc->Format;
|
||||||
desc.SampleDesc = pSwapChainDesc->SampleDesc;
|
desc.SampleDesc = pSwapChainDesc->SampleDesc;
|
||||||
desc.Usage = D3D11_USAGE_DEFAULT;
|
desc.Usage = D3D11_USAGE_DEFAULT;
|
||||||
desc.BindFlags = D3D11_BIND_RENDER_TARGET
|
desc.BindFlags = D3D11_BIND_RENDER_TARGET
|
||||||
|
@ -54,7 +54,7 @@ namespace dxvk {
|
|||||||
void** ppvObject);
|
void** ppvObject);
|
||||||
|
|
||||||
HRESULT STDMETHODCALLTYPE CreateSwapChainBackBuffer(
|
HRESULT STDMETHODCALLTYPE CreateSwapChainBackBuffer(
|
||||||
const DXGI_SWAP_CHAIN_DESC* pSwapChainDesc,
|
const DXGI_SWAP_CHAIN_DESC1* pSwapChainDesc,
|
||||||
IDXGIVkBackBuffer** ppInterface);
|
IDXGIVkBackBuffer** ppInterface);
|
||||||
|
|
||||||
HRESULT STDMETHODCALLTYPE FlushRenderingCommands();
|
HRESULT STDMETHODCALLTYPE FlushRenderingCommands();
|
||||||
|
@ -34,7 +34,17 @@ namespace dxvk {
|
|||||||
m_analysis->uavInfos[registerId].accessAtomicOp = true;
|
m_analysis->uavInfos[registerId].accessAtomicOp = true;
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
case DxbcInstClass::TextureSample:
|
||||||
|
case DxbcInstClass::VectorDeriv: {
|
||||||
|
m_analysis->usesDerivatives = true;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case DxbcInstClass::ControlFlow: {
|
||||||
|
if (ins.op == DxbcOpcode::Discard)
|
||||||
|
m_analysis->usesKill = true;
|
||||||
|
} break;
|
||||||
|
|
||||||
case DxbcInstClass::TypedUavLoad: {
|
case DxbcInstClass::TypedUavLoad: {
|
||||||
const uint32_t registerId = ins.src[1].idx[0].offset;
|
const uint32_t registerId = ins.src[1].idx[0].offset;
|
||||||
m_analysis->uavInfos[registerId].accessTypedLoad = true;
|
m_analysis->uavInfos[registerId].accessTypedLoad = true;
|
||||||
|
@ -37,6 +37,9 @@ namespace dxvk {
|
|||||||
|
|
||||||
DxbcClipCullInfo clipCullIn;
|
DxbcClipCullInfo clipCullIn;
|
||||||
DxbcClipCullInfo clipCullOut;
|
DxbcClipCullInfo clipCullOut;
|
||||||
|
|
||||||
|
bool usesDerivatives = false;
|
||||||
|
bool usesKill = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -41,6 +41,13 @@ namespace dxvk {
|
|||||||
m_oRegs.at(i) = 0;
|
m_oRegs.at(i) = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Clear spec constants
|
||||||
|
for (uint32_t i = 0; i < m_specConstants.size(); i++) {
|
||||||
|
m_specConstants.at(i) = DxbcRegisterValue {
|
||||||
|
DxbcVectorType { DxbcScalarType::Uint32, 0 },
|
||||||
|
0 };
|
||||||
|
}
|
||||||
|
|
||||||
this->emitInit();
|
this->emitInit();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -277,6 +284,9 @@ namespace dxvk {
|
|||||||
case DxbcOpcode::DclThreadGroup:
|
case DxbcOpcode::DclThreadGroup:
|
||||||
return this->emitDclThreadGroup(ins);
|
return this->emitDclThreadGroup(ins);
|
||||||
|
|
||||||
|
case DxbcOpcode::DclGsInstanceCount:
|
||||||
|
return this->emitDclGsInstanceCount(ins);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
Logger::warn(
|
Logger::warn(
|
||||||
str::format("DxbcCompiler: Unhandled opcode: ",
|
str::format("DxbcCompiler: Unhandled opcode: ",
|
||||||
@ -456,7 +466,6 @@ namespace dxvk {
|
|||||||
} break;
|
} break;
|
||||||
|
|
||||||
case DxbcOperandType::InputCoverageMask: {
|
case DxbcOperandType::InputCoverageMask: {
|
||||||
m_module.enableCapability(spv::CapabilitySampleRateShading);
|
|
||||||
m_ps.builtinSampleMaskIn = emitNewBuiltinVariable({
|
m_ps.builtinSampleMaskIn = emitNewBuiltinVariable({
|
||||||
{ DxbcScalarType::Uint32, 1, 1 },
|
{ DxbcScalarType::Uint32, 1, 1 },
|
||||||
spv::StorageClassInput },
|
spv::StorageClassInput },
|
||||||
@ -465,7 +474,6 @@ namespace dxvk {
|
|||||||
} break;
|
} break;
|
||||||
|
|
||||||
case DxbcOperandType::OutputCoverageMask: {
|
case DxbcOperandType::OutputCoverageMask: {
|
||||||
m_module.enableCapability(spv::CapabilitySampleRateShading);
|
|
||||||
m_ps.builtinSampleMaskOut = emitNewBuiltinVariable({
|
m_ps.builtinSampleMaskOut = emitNewBuiltinVariable({
|
||||||
{ DxbcScalarType::Uint32, 1, 1 },
|
{ DxbcScalarType::Uint32, 1, 1 },
|
||||||
spv::StorageClassOutput },
|
spv::StorageClassOutput },
|
||||||
@ -547,6 +555,14 @@ namespace dxvk {
|
|||||||
// output arrays, so there's nothing left to do.
|
// output arrays, so there's nothing left to do.
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
case DxbcOperandType::InputGsInstanceId: {
|
||||||
|
m_gs.builtinInvocationId = emitNewBuiltinVariable({
|
||||||
|
{ DxbcScalarType::Uint32, 1, 0 },
|
||||||
|
spv::StorageClassInput },
|
||||||
|
spv::BuiltInInvocationId,
|
||||||
|
"vInstanceID");
|
||||||
|
} break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
Logger::err(str::format(
|
Logger::err(str::format(
|
||||||
"DxbcCompiler: Unsupported operand type declaration: ",
|
"DxbcCompiler: Unsupported operand type declaration: ",
|
||||||
@ -819,7 +835,6 @@ namespace dxvk {
|
|||||||
case DxbcResourceDim::Buffer: m_module.enableCapability(spv::CapabilityImageBuffer); break;
|
case DxbcResourceDim::Buffer: m_module.enableCapability(spv::CapabilityImageBuffer); break;
|
||||||
case DxbcResourceDim::Texture1D: m_module.enableCapability(spv::CapabilityImage1D); break;
|
case DxbcResourceDim::Texture1D: m_module.enableCapability(spv::CapabilityImage1D); break;
|
||||||
case DxbcResourceDim::Texture1DArr: m_module.enableCapability(spv::CapabilityImage1D); break;
|
case DxbcResourceDim::Texture1DArr: m_module.enableCapability(spv::CapabilityImage1D); break;
|
||||||
case DxbcResourceDim::TextureCube: m_module.enableCapability(spv::CapabilityImageCubeArray); break;
|
|
||||||
case DxbcResourceDim::TextureCubeArr: m_module.enableCapability(spv::CapabilityImageCubeArray); break;
|
case DxbcResourceDim::TextureCubeArr: m_module.enableCapability(spv::CapabilityImageCubeArray); break;
|
||||||
case DxbcResourceDim::Texture2DMs: m_module.enableCapability(spv::CapabilityImageMSArray); break;
|
case DxbcResourceDim::Texture2DMs: m_module.enableCapability(spv::CapabilityImageMSArray); break;
|
||||||
case DxbcResourceDim::Texture2DMsArr: m_module.enableCapability(spv::CapabilityImageMSArray); break;
|
case DxbcResourceDim::Texture2DMsArr: m_module.enableCapability(spv::CapabilityImageMSArray); break;
|
||||||
@ -955,7 +970,7 @@ namespace dxvk {
|
|||||||
const DxbcScalarType sampledType = DxbcScalarType::Uint32;
|
const DxbcScalarType sampledType = DxbcScalarType::Uint32;
|
||||||
const uint32_t sampledTypeId = getScalarTypeId(sampledType);
|
const uint32_t sampledTypeId = getScalarTypeId(sampledType);
|
||||||
|
|
||||||
const DxbcImageInfo typeInfo = { spv::DimBuffer, 0, 0, isUav ? 2u : 1u, 0u, VK_IMAGE_VIEW_TYPE_MAX_ENUM };
|
const DxbcImageInfo typeInfo = { spv::DimBuffer, 0, 0, isUav ? 2u : 1u, VK_IMAGE_VIEW_TYPE_MAX_ENUM };
|
||||||
|
|
||||||
// Declare the resource type
|
// Declare the resource type
|
||||||
const uint32_t resTypeId = m_module.defImageType(sampledTypeId,
|
const uint32_t resTypeId = m_module.defImageType(sampledTypeId,
|
||||||
@ -1221,6 +1236,13 @@ namespace dxvk {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void DxbcCompiler::emitDclGsInstanceCount(const DxbcShaderInstruction& ins) {
|
||||||
|
// dcl_gs_instance_count has one operand:
|
||||||
|
// (imm0) Number of geometry shader invocations
|
||||||
|
m_module.setInvocations(m_entryPointId, ins.imm[0].u32);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
uint32_t DxbcCompiler::emitDclUavCounter(uint32_t regId) {
|
uint32_t DxbcCompiler::emitDclUavCounter(uint32_t regId) {
|
||||||
// Declare a structure type which holds the UAV counter
|
// Declare a structure type which holds the UAV counter
|
||||||
if (m_uavCtrStructType == 0) {
|
if (m_uavCtrStructType == 0) {
|
||||||
@ -1981,9 +2003,27 @@ namespace dxvk {
|
|||||||
// (dst0) Register that receives the result
|
// (dst0) Register that receives the result
|
||||||
// (dst1) Destination u# or g# register
|
// (dst1) Destination u# or g# register
|
||||||
// (srcX) As above
|
// (srcX) As above
|
||||||
|
const DxbcBufferInfo bufferInfo = getBufferInfo(ins.dst[ins.dstCount - 1]);
|
||||||
|
|
||||||
const bool isImm = ins.dstCount == 2;
|
const bool isImm = ins.dstCount == 2;
|
||||||
const bool isUav = ins.dst[ins.dstCount - 1].type == DxbcOperandType::UnorderedAccessView;
|
const bool isUav = ins.dst[ins.dstCount - 1].type == DxbcOperandType::UnorderedAccessView;
|
||||||
|
|
||||||
|
// Perform atomic operations on UAVs only if the UAV
|
||||||
|
// is bound and if there is nothing else stopping us.
|
||||||
|
DxbcConditional cond;
|
||||||
|
|
||||||
|
if (isUav) {
|
||||||
|
uint32_t writeTest = emitUavWriteTest(bufferInfo);
|
||||||
|
|
||||||
|
cond.labelIf = m_module.allocateId();
|
||||||
|
cond.labelEnd = m_module.allocateId();
|
||||||
|
|
||||||
|
m_module.opSelectionMerge(cond.labelEnd, spv::SelectionControlMaskNone);
|
||||||
|
m_module.opBranchConditional(writeTest, cond.labelIf, cond.labelEnd);
|
||||||
|
|
||||||
|
m_module.opLabel(cond.labelIf);
|
||||||
|
}
|
||||||
|
|
||||||
// Retrieve destination pointer for the atomic operation>
|
// Retrieve destination pointer for the atomic operation>
|
||||||
const DxbcRegisterPointer pointer = emitGetAtomicPointer(
|
const DxbcRegisterPointer pointer = emitGetAtomicPointer(
|
||||||
ins.dst[ins.dstCount - 1], ins.src[0]);
|
ins.dst[ins.dstCount - 1], ins.src[0]);
|
||||||
@ -2104,6 +2144,12 @@ namespace dxvk {
|
|||||||
// register if this is an imm_atomic_* opcode.
|
// register if this is an imm_atomic_* opcode.
|
||||||
if (isImm)
|
if (isImm)
|
||||||
emitRegisterStore(ins.dst[0], value);
|
emitRegisterStore(ins.dst[0], value);
|
||||||
|
|
||||||
|
// End conditional block
|
||||||
|
if (isUav) {
|
||||||
|
m_module.opBranch(cond.labelEnd);
|
||||||
|
m_module.opLabel (cond.labelEnd);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -2111,12 +2157,25 @@ namespace dxvk {
|
|||||||
// imm_atomic_alloc and imm_atomic_consume have the following operands:
|
// imm_atomic_alloc and imm_atomic_consume have the following operands:
|
||||||
// (dst0) The register that will hold the old counter value
|
// (dst0) The register that will hold the old counter value
|
||||||
// (dst1) The UAV whose counter is going to be modified
|
// (dst1) The UAV whose counter is going to be modified
|
||||||
// TODO check if the corresponding UAV is bound
|
const DxbcBufferInfo bufferInfo = getBufferInfo(ins.dst[1]);
|
||||||
|
|
||||||
const uint32_t registerId = ins.dst[1].idx[0].offset;
|
const uint32_t registerId = ins.dst[1].idx[0].offset;
|
||||||
|
|
||||||
if (m_uavs.at(registerId).ctrId == 0)
|
if (m_uavs.at(registerId).ctrId == 0)
|
||||||
m_uavs.at(registerId).ctrId = emitDclUavCounter(registerId);
|
m_uavs.at(registerId).ctrId = emitDclUavCounter(registerId);
|
||||||
|
|
||||||
|
// Only perform the operation if the UAV is bound
|
||||||
|
uint32_t writeTest = emitUavWriteTest(bufferInfo);
|
||||||
|
|
||||||
|
DxbcConditional cond;
|
||||||
|
cond.labelIf = m_module.allocateId();
|
||||||
|
cond.labelEnd = m_module.allocateId();
|
||||||
|
|
||||||
|
m_module.opSelectionMerge(cond.labelEnd, spv::SelectionControlMaskNone);
|
||||||
|
m_module.opBranchConditional(writeTest, cond.labelIf, cond.labelEnd);
|
||||||
|
|
||||||
|
m_module.opLabel(cond.labelIf);
|
||||||
|
|
||||||
// Get a pointer to the atomic counter in question
|
// Get a pointer to the atomic counter in question
|
||||||
DxbcRegisterInfo ptrType;
|
DxbcRegisterInfo ptrType;
|
||||||
ptrType.type.ctype = DxbcScalarType::Uint32;
|
ptrType.type.ctype = DxbcScalarType::Uint32;
|
||||||
@ -2165,6 +2224,10 @@ namespace dxvk {
|
|||||||
|
|
||||||
// Store the result
|
// Store the result
|
||||||
emitRegisterStore(ins.dst[0], value);
|
emitRegisterStore(ins.dst[0], value);
|
||||||
|
|
||||||
|
// End conditional block
|
||||||
|
m_module.opBranch(cond.labelEnd);
|
||||||
|
m_module.opLabel (cond.labelEnd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -3232,23 +3295,37 @@ namespace dxvk {
|
|||||||
// (dst0) The destination UAV
|
// (dst0) The destination UAV
|
||||||
// (src0) The texture or buffer coordinates
|
// (src0) The texture or buffer coordinates
|
||||||
// (src1) The value to store
|
// (src1) The value to store
|
||||||
const uint32_t registerId = ins.dst[0].idx[0].offset;
|
const DxbcBufferInfo uavInfo = getBufferInfo(ins.dst[0]);
|
||||||
const DxbcUav uavInfo = m_uavs.at(registerId);
|
|
||||||
|
// Execute write op only if the UAV is bound
|
||||||
|
uint32_t writeTest = emitUavWriteTest(uavInfo);
|
||||||
|
|
||||||
|
DxbcConditional cond;
|
||||||
|
cond.labelIf = m_module.allocateId();
|
||||||
|
cond.labelEnd = m_module.allocateId();
|
||||||
|
|
||||||
|
m_module.opSelectionMerge (cond.labelEnd, spv::SelectionControlMaskNone);
|
||||||
|
m_module.opBranchConditional(writeTest, cond.labelIf, cond.labelEnd);
|
||||||
|
|
||||||
|
m_module.opLabel(cond.labelIf);
|
||||||
|
|
||||||
// Load texture coordinates
|
// Load texture coordinates
|
||||||
DxbcRegisterValue texCoord = emitLoadTexCoord(
|
DxbcRegisterValue texCoord = emitLoadTexCoord(ins.src[0], uavInfo.image);
|
||||||
ins.src[0], uavInfo.imageInfo);
|
|
||||||
|
|
||||||
// Load the value that will be written to the image. We'll
|
// Load the value that will be written to the image. We'll
|
||||||
// have to cast it to the component type of the image.
|
// have to cast it to the component type of the image.
|
||||||
const DxbcRegisterValue texValue = emitRegisterBitcast(
|
const DxbcRegisterValue texValue = emitRegisterBitcast(
|
||||||
emitRegisterLoad(ins.src[1], DxbcRegMask(true, true, true, true)),
|
emitRegisterLoad(ins.src[1], DxbcRegMask(true, true, true, true)),
|
||||||
uavInfo.sampledType);
|
uavInfo.stype);
|
||||||
|
|
||||||
// Write the given value to the image
|
// Write the given value to the image
|
||||||
m_module.opImageWrite(
|
m_module.opImageWrite(
|
||||||
m_module.opLoad(uavInfo.imageTypeId, uavInfo.varId),
|
m_module.opLoad(uavInfo.typeId, uavInfo.varId),
|
||||||
texCoord.id, texValue.id, SpirvImageOperands());
|
texCoord.id, texValue.id, SpirvImageOperands());
|
||||||
|
|
||||||
|
// End conditional block
|
||||||
|
m_module.opBranch(cond.labelEnd);
|
||||||
|
m_module.opLabel (cond.labelEnd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -3258,29 +3335,21 @@ namespace dxvk {
|
|||||||
const DxbcRegisterValue condition = emitRegisterLoad(
|
const DxbcRegisterValue condition = emitRegisterLoad(
|
||||||
ins.src[0], DxbcRegMask(true, false, false, false));
|
ins.src[0], DxbcRegMask(true, false, false, false));
|
||||||
|
|
||||||
const DxbcRegisterValue zeroTest = emitRegisterZeroTest(
|
|
||||||
condition, ins.controls.zeroTest());
|
|
||||||
|
|
||||||
// Declare the 'if' block. We do not know if there
|
// Declare the 'if' block. We do not know if there
|
||||||
// will be an 'else' block or not, so we'll assume
|
// will be an 'else' block or not, so we'll assume
|
||||||
// that there is one and leave it empty otherwise.
|
// that there is one and leave it empty otherwise.
|
||||||
DxbcCfgBlock block;
|
DxbcCfgBlock block;
|
||||||
block.type = DxbcCfgBlockType::If;
|
block.type = DxbcCfgBlockType::If;
|
||||||
|
block.b_if.ztestId = emitRegisterZeroTest(condition, ins.controls.zeroTest()).id;
|
||||||
block.b_if.labelIf = m_module.allocateId();
|
block.b_if.labelIf = m_module.allocateId();
|
||||||
block.b_if.labelElse = m_module.allocateId();
|
block.b_if.labelElse = 0;
|
||||||
block.b_if.labelEnd = m_module.allocateId();
|
block.b_if.labelEnd = m_module.allocateId();
|
||||||
block.b_if.hadElse = false;
|
block.b_if.headerPtr = m_module.getInsertionPtr();
|
||||||
m_controlFlowBlocks.push_back(block);
|
m_controlFlowBlocks.push_back(block);
|
||||||
|
|
||||||
m_module.opSelectionMerge(
|
// We'll insert the branch instruction when closing
|
||||||
block.b_if.labelEnd,
|
// the block, since we don't know whether or not an
|
||||||
spv::SelectionControlMaskNone);
|
// else block is needed right now.
|
||||||
|
|
||||||
m_module.opBranchConditional(
|
|
||||||
zeroTest.id,
|
|
||||||
block.b_if.labelIf,
|
|
||||||
block.b_if.labelElse);
|
|
||||||
|
|
||||||
m_module.opLabel(block.b_if.labelIf);
|
m_module.opLabel(block.b_if.labelIf);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3288,13 +3357,13 @@ namespace dxvk {
|
|||||||
void DxbcCompiler::emitControlFlowElse(const DxbcShaderInstruction& ins) {
|
void DxbcCompiler::emitControlFlowElse(const DxbcShaderInstruction& ins) {
|
||||||
if (m_controlFlowBlocks.size() == 0
|
if (m_controlFlowBlocks.size() == 0
|
||||||
|| m_controlFlowBlocks.back().type != DxbcCfgBlockType::If
|
|| m_controlFlowBlocks.back().type != DxbcCfgBlockType::If
|
||||||
|| m_controlFlowBlocks.back().b_if.hadElse)
|
|| m_controlFlowBlocks.back().b_if.labelElse != 0)
|
||||||
throw DxvkError("DxbcCompiler: 'Else' without 'If' found");
|
throw DxvkError("DxbcCompiler: 'Else' without 'If' found");
|
||||||
|
|
||||||
// Set the 'Else' flag so that we do
|
// Set the 'Else' flag so that we do
|
||||||
// not insert a dummy block on 'EndIf'
|
// not insert a dummy block on 'EndIf'
|
||||||
DxbcCfgBlock& block = m_controlFlowBlocks.back();
|
DxbcCfgBlock& block = m_controlFlowBlocks.back();
|
||||||
block.b_if.hadElse = true;
|
block.b_if.labelElse = m_module.allocateId();
|
||||||
|
|
||||||
// Close the 'If' block by branching to
|
// Close the 'If' block by branching to
|
||||||
// the merge block we declared earlier
|
// the merge block we declared earlier
|
||||||
@ -3309,21 +3378,28 @@ namespace dxvk {
|
|||||||
throw DxvkError("DxbcCompiler: 'EndIf' without 'If' found");
|
throw DxvkError("DxbcCompiler: 'EndIf' without 'If' found");
|
||||||
|
|
||||||
// Remove the block from the stack, it's closed
|
// Remove the block from the stack, it's closed
|
||||||
const DxbcCfgBlock block = m_controlFlowBlocks.back();
|
DxbcCfgBlock block = m_controlFlowBlocks.back();
|
||||||
m_controlFlowBlocks.pop_back();
|
m_controlFlowBlocks.pop_back();
|
||||||
|
|
||||||
|
// Write out the 'if' header
|
||||||
|
m_module.beginInsertion(block.b_if.headerPtr);
|
||||||
|
|
||||||
|
m_module.opSelectionMerge(
|
||||||
|
block.b_if.labelEnd,
|
||||||
|
spv::SelectionControlMaskNone);
|
||||||
|
|
||||||
|
m_module.opBranchConditional(
|
||||||
|
block.b_if.ztestId,
|
||||||
|
block.b_if.labelIf,
|
||||||
|
block.b_if.labelElse != 0
|
||||||
|
? block.b_if.labelElse
|
||||||
|
: block.b_if.labelEnd);
|
||||||
|
|
||||||
|
m_module.endInsertion();
|
||||||
|
|
||||||
// End the active 'if' or 'else' block
|
// End the active 'if' or 'else' block
|
||||||
m_module.opBranch(block.b_if.labelEnd);
|
m_module.opBranch(block.b_if.labelEnd);
|
||||||
|
m_module.opLabel (block.b_if.labelEnd);
|
||||||
// If there was no 'else' block in this construct, we still
|
|
||||||
// have to declare it because we used it as a branch target.
|
|
||||||
if (!block.b_if.hadElse) {
|
|
||||||
m_module.opLabel (block.b_if.labelElse);
|
|
||||||
m_module.opBranch(block.b_if.labelEnd);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Declare the merge block
|
|
||||||
m_module.opLabel(block.b_if.labelEnd);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -3589,21 +3665,26 @@ namespace dxvk {
|
|||||||
const DxbcRegisterValue zeroTest = emitRegisterZeroTest(
|
const DxbcRegisterValue zeroTest = emitRegisterZeroTest(
|
||||||
condition, ins.controls.zeroTest());
|
condition, ins.controls.zeroTest());
|
||||||
|
|
||||||
// Insert a Pseudo-'If' block
|
if (m_ps.killState == 0) {
|
||||||
const uint32_t discardBlock = m_module.allocateId();
|
DxbcConditional cond;
|
||||||
const uint32_t mergeBlock = m_module.allocateId();
|
cond.labelIf = m_module.allocateId();
|
||||||
|
cond.labelEnd = m_module.allocateId();
|
||||||
m_module.opSelectionMerge(mergeBlock,
|
|
||||||
spv::SelectionControlMaskNone);
|
m_module.opSelectionMerge(cond.labelIf, spv::SelectionControlMaskNone);
|
||||||
|
m_module.opBranchConditional(zeroTest.id, cond.labelIf, cond.labelEnd);
|
||||||
m_module.opBranchConditional(
|
|
||||||
zeroTest.id, discardBlock, mergeBlock);
|
// OpKill terminates the block
|
||||||
|
m_module.opLabel(cond.labelIf);
|
||||||
// OpKill terminates the block
|
m_module.opKill();
|
||||||
m_module.opLabel(discardBlock);
|
|
||||||
m_module.opKill();
|
m_module.opLabel(cond.labelEnd);
|
||||||
|
} else {
|
||||||
m_module.opLabel(mergeBlock);
|
uint32_t typeId = m_module.defBoolType();
|
||||||
|
|
||||||
|
uint32_t killState = m_module.opLoad (typeId, m_ps.killState);
|
||||||
|
killState = m_module.opLogicalOr(typeId, killState, zeroTest.id);
|
||||||
|
m_module.opStore(m_ps.killState, killState);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -4285,6 +4366,11 @@ namespace dxvk {
|
|||||||
return DxbcRegisterPointer {
|
return DxbcRegisterPointer {
|
||||||
{ DxbcScalarType::Uint32, 1 },
|
{ DxbcScalarType::Uint32, 1 },
|
||||||
getCurrentHsForkJoinPhase()->instanceIdPtr };
|
getCurrentHsForkJoinPhase()->instanceIdPtr };
|
||||||
|
|
||||||
|
case DxbcOperandType::InputGsInstanceId:
|
||||||
|
return DxbcRegisterPointer {
|
||||||
|
{ DxbcScalarType::Uint32, 1 },
|
||||||
|
m_gs.builtinInvocationId };
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw DxvkError(str::format(
|
throw DxvkError(str::format(
|
||||||
@ -4441,11 +4527,27 @@ namespace dxvk {
|
|||||||
// Cast source value to the expected data type
|
// Cast source value to the expected data type
|
||||||
value = emitRegisterBitcast(value, DxbcScalarType::Uint32);
|
value = emitRegisterBitcast(value, DxbcScalarType::Uint32);
|
||||||
|
|
||||||
// Shared memory is not accessed through a texel buffer view
|
// Thread Group Shared Memory is not accessed through a texel buffer view
|
||||||
const bool isTgsm = operand.type == DxbcOperandType::ThreadGroupSharedMemory;
|
const bool isUav = operand.type == DxbcOperandType::UnorderedAccessView;
|
||||||
|
|
||||||
const uint32_t bufferId = isTgsm
|
// Perform UAV writes only if the UAV is bound and if there
|
||||||
? 0 : m_module.opLoad(bufferInfo.typeId, bufferInfo.varId);
|
// is nothing else preventing us from writing to it.
|
||||||
|
DxbcConditional cond;
|
||||||
|
|
||||||
|
if (isUav) {
|
||||||
|
uint32_t writeTest = emitUavWriteTest(bufferInfo);
|
||||||
|
|
||||||
|
cond.labelIf = m_module.allocateId();
|
||||||
|
cond.labelEnd = m_module.allocateId();
|
||||||
|
|
||||||
|
m_module.opSelectionMerge(cond.labelEnd, spv::SelectionControlMaskNone);
|
||||||
|
m_module.opBranchConditional(writeTest, cond.labelIf, cond.labelEnd);
|
||||||
|
|
||||||
|
m_module.opLabel(cond.labelIf);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Perform the actual write operation
|
||||||
|
const uint32_t bufferId = isUav ? m_module.opLoad(bufferInfo.typeId, bufferInfo.varId) : 0;
|
||||||
|
|
||||||
const uint32_t scalarTypeId = getVectorTypeId({ DxbcScalarType::Uint32, 1 });
|
const uint32_t scalarTypeId = getVectorTypeId({ DxbcScalarType::Uint32, 1 });
|
||||||
const uint32_t vectorTypeId = getVectorTypeId({ DxbcScalarType::Uint32, 4 });
|
const uint32_t vectorTypeId = getVectorTypeId({ DxbcScalarType::Uint32, 4 });
|
||||||
@ -4494,6 +4596,12 @@ namespace dxvk {
|
|||||||
srcComponentIndex += 1;
|
srcComponentIndex += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// End conditional block
|
||||||
|
if (isUav) {
|
||||||
|
m_module.opBranch(cond.labelEnd);
|
||||||
|
m_module.opLabel (cond.labelEnd);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -4538,15 +4646,21 @@ namespace dxvk {
|
|||||||
|
|
||||||
DxbcRegisterValue DxbcCompiler::emitQueryTextureSamples(
|
DxbcRegisterValue DxbcCompiler::emitQueryTextureSamples(
|
||||||
const DxbcRegister& resource) {
|
const DxbcRegister& resource) {
|
||||||
const DxbcBufferInfo info = getBufferInfo(resource);
|
if (resource.type == DxbcOperandType::Rasterizer) {
|
||||||
|
// SPIR-V has no gl_NumSamples equivalent, so we have
|
||||||
DxbcRegisterValue result;
|
// to work around it using a specialization constant
|
||||||
result.type.ctype = DxbcScalarType::Uint32;
|
return getSpecConstant(DxvkSpecConstantId::RasterizerSampleCount);
|
||||||
result.type.ccount = 1;
|
} else {
|
||||||
result.id = m_module.opImageQuerySamples(
|
DxbcBufferInfo info = getBufferInfo(resource);
|
||||||
getVectorTypeId(result.type),
|
|
||||||
m_module.opLoad(info.typeId, info.varId));
|
DxbcRegisterValue result;
|
||||||
return result;
|
result.type.ctype = DxbcScalarType::Uint32;
|
||||||
|
result.type.ccount = 1;
|
||||||
|
result.id = m_module.opImageQuerySamples(
|
||||||
|
getVectorTypeId(result.type),
|
||||||
|
m_module.opLoad(info.typeId, info.varId));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -4570,15 +4684,6 @@ namespace dxvk {
|
|||||||
m_module.opLoad(info.typeId, info.varId));
|
m_module.opLoad(info.typeId, info.varId));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (info.image.array && !info.image.layered) {
|
|
||||||
const uint32_t index = result.type.ccount - 1;
|
|
||||||
const uint32_t zero = m_module.constu32(0);
|
|
||||||
|
|
||||||
result.id = m_module.opCompositeInsert(
|
|
||||||
getVectorTypeId(result.type),
|
|
||||||
zero, result.id, 1, &index);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4623,22 +4728,6 @@ namespace dxvk {
|
|||||||
coordVector, DxbcRegMask::firstN(dim));
|
coordVector, DxbcRegMask::firstN(dim));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (imageInfo.array && !imageInfo.layered) {
|
|
||||||
const uint32_t index = dim - 1;
|
|
||||||
const uint32_t zero = [&] {
|
|
||||||
switch (coordVector.type.ctype) {
|
|
||||||
case DxbcScalarType::Sint32: return m_module.consti32(0);
|
|
||||||
case DxbcScalarType::Uint32: return m_module.constu32(0);
|
|
||||||
case DxbcScalarType::Float32: return m_module.constf32(0.0f);
|
|
||||||
default: throw DxvkError("Dxbc: Invalid tex coord type");
|
|
||||||
}
|
|
||||||
}();
|
|
||||||
|
|
||||||
coordVector.id = m_module.opCompositeInsert(
|
|
||||||
getVectorTypeId(coordVector.type),
|
|
||||||
zero, coordVector.id, 1, &index);
|
|
||||||
}
|
|
||||||
|
|
||||||
return coordVector;
|
return coordVector;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4784,6 +4873,43 @@ namespace dxvk {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DxbcRegisterValue DxbcCompiler::getSpecConstant(DxvkSpecConstantId specId) {
|
||||||
|
const uint32_t specIdOffset = uint32_t(specId) - uint32_t(DxvkSpecConstantId::SpecConstantIdMin);
|
||||||
|
|
||||||
|
// Look up spec constant in the array
|
||||||
|
DxbcRegisterValue value = m_specConstants.at(specIdOffset);
|
||||||
|
|
||||||
|
if (value.id != 0)
|
||||||
|
return value;
|
||||||
|
|
||||||
|
// Declare a new specialization constant if needed
|
||||||
|
DxbcSpecConstant info = getSpecConstantProperties(specId);
|
||||||
|
|
||||||
|
value.type.ctype = info.ctype;
|
||||||
|
value.type.ccount = info.ccount;
|
||||||
|
value.id = m_module.specConst32(
|
||||||
|
getVectorTypeId(value.type),
|
||||||
|
info.value);
|
||||||
|
|
||||||
|
m_module.decorateSpecId(value.id, uint32_t(specId));
|
||||||
|
m_module.setDebugName(value.id, info.name);
|
||||||
|
|
||||||
|
m_specConstants.at(specIdOffset) = value;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DxbcSpecConstant DxbcCompiler::getSpecConstantProperties(DxvkSpecConstantId specId) {
|
||||||
|
static const std::array<DxbcSpecConstant,
|
||||||
|
uint32_t(DxvkSpecConstantId::SpecConstantIdMax) -
|
||||||
|
uint32_t(DxvkSpecConstantId::SpecConstantIdMin) + 1> s_specConstants = {{
|
||||||
|
{ DxbcScalarType::Uint32, 1, 1, "RasterizerSampleCount" },
|
||||||
|
}};
|
||||||
|
|
||||||
|
return s_specConstants.at(uint32_t(specId) - uint32_t(DxvkSpecConstantId::SpecConstantIdMin));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void DxbcCompiler::emitInputSetup() {
|
void DxbcCompiler::emitInputSetup() {
|
||||||
// Copy all defined v# registers into the input array
|
// Copy all defined v# registers into the input array
|
||||||
const uint32_t vecTypeId = m_module.defVectorType(m_module.defFloatType(32), 4);
|
const uint32_t vecTypeId = m_module.defVectorType(m_module.defFloatType(32), 4);
|
||||||
@ -5429,6 +5555,21 @@ namespace dxvk {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint32_t DxbcCompiler::emitUavWriteTest(const DxbcBufferInfo& uav) {
|
||||||
|
uint32_t typeId = m_module.defBoolType();
|
||||||
|
uint32_t testId = uav.specId;
|
||||||
|
|
||||||
|
if (m_ps.killState != 0) {
|
||||||
|
uint32_t killState = m_module.opLoad(typeId, m_ps.killState);
|
||||||
|
|
||||||
|
testId = m_module.opLogicalAnd(typeId, testId,
|
||||||
|
m_module.opLogicalNot(typeId, killState));
|
||||||
|
}
|
||||||
|
|
||||||
|
return testId;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void DxbcCompiler::emitInit() {
|
void DxbcCompiler::emitInit() {
|
||||||
// Set up common capabilities for all shaders
|
// Set up common capabilities for all shaders
|
||||||
m_module.enableCapability(spv::CapabilityShader);
|
m_module.enableCapability(spv::CapabilityShader);
|
||||||
@ -5633,6 +5774,16 @@ namespace dxvk {
|
|||||||
spv::BuiltInCullDistance,
|
spv::BuiltInCullDistance,
|
||||||
spv::StorageClassInput);
|
spv::StorageClassInput);
|
||||||
|
|
||||||
|
// We may have to defer kill operations to the end of
|
||||||
|
// the shader in order to keep derivatives correct.
|
||||||
|
if (m_analysis->usesKill && m_analysis->usesDerivatives && m_options.test(DxbcOption::DeferKill)) {
|
||||||
|
m_ps.killState = m_module.newVarInit(
|
||||||
|
m_module.defPointerType(m_module.defBoolType(), spv::StorageClassPrivate),
|
||||||
|
spv::StorageClassPrivate, m_module.constBool(false));
|
||||||
|
|
||||||
|
m_module.setDebugName(m_ps.killState, "ps_kill");
|
||||||
|
}
|
||||||
|
|
||||||
// Main function of the pixel shader
|
// Main function of the pixel shader
|
||||||
m_ps.functionId = m_module.allocateId();
|
m_ps.functionId = m_module.allocateId();
|
||||||
m_module.setDebugName(m_ps.functionId, "ps_main");
|
m_module.setDebugName(m_ps.functionId, "ps_main");
|
||||||
@ -5730,9 +5881,27 @@ namespace dxvk {
|
|||||||
this->emitInputSetup();
|
this->emitInputSetup();
|
||||||
this->emitClipCullLoad(DxbcSystemValue::ClipDistance, m_clipDistances);
|
this->emitClipCullLoad(DxbcSystemValue::ClipDistance, m_clipDistances);
|
||||||
this->emitClipCullLoad(DxbcSystemValue::CullDistance, m_cullDistances);
|
this->emitClipCullLoad(DxbcSystemValue::CullDistance, m_cullDistances);
|
||||||
|
|
||||||
m_module.opFunctionCall(
|
m_module.opFunctionCall(
|
||||||
m_module.defVoidType(),
|
m_module.defVoidType(),
|
||||||
m_ps.functionId, 0, nullptr);
|
m_ps.functionId, 0, nullptr);
|
||||||
|
|
||||||
|
if (m_ps.killState != 0) {
|
||||||
|
DxbcConditional cond;
|
||||||
|
cond.labelIf = m_module.allocateId();
|
||||||
|
cond.labelEnd = m_module.allocateId();
|
||||||
|
|
||||||
|
uint32_t killTest = m_module.opLoad(m_module.defBoolType(), m_ps.killState);
|
||||||
|
|
||||||
|
m_module.opSelectionMerge(cond.labelEnd, spv::SelectionControlMaskNone);
|
||||||
|
m_module.opBranchConditional(killTest, cond.labelIf, cond.labelEnd);
|
||||||
|
|
||||||
|
m_module.opLabel(cond.labelIf);
|
||||||
|
m_module.opKill();
|
||||||
|
|
||||||
|
m_module.opLabel(cond.labelEnd);
|
||||||
|
}
|
||||||
|
|
||||||
this->emitOutputSetup();
|
this->emitOutputSetup();
|
||||||
this->emitMainFunctionEnd();
|
this->emitMainFunctionEnd();
|
||||||
}
|
}
|
||||||
@ -6256,25 +6425,20 @@ namespace dxvk {
|
|||||||
bool isUav) const {
|
bool isUav) const {
|
||||||
DxbcImageInfo typeInfo = [resourceType, isUav] () -> DxbcImageInfo {
|
DxbcImageInfo typeInfo = [resourceType, isUav] () -> DxbcImageInfo {
|
||||||
switch (resourceType) {
|
switch (resourceType) {
|
||||||
case DxbcResourceDim::Buffer: return { spv::DimBuffer, 0, 0, isUav ? 2u : 1u, 0u, VK_IMAGE_VIEW_TYPE_MAX_ENUM };
|
case DxbcResourceDim::Buffer: return { spv::DimBuffer, 0, 0, isUav ? 2u : 1u, VK_IMAGE_VIEW_TYPE_MAX_ENUM };
|
||||||
case DxbcResourceDim::Texture1D: return { spv::Dim1D, 0, 0, isUav ? 2u : 1u, 0u, VK_IMAGE_VIEW_TYPE_1D };
|
case DxbcResourceDim::Texture1D: return { spv::Dim1D, 0, 0, isUav ? 2u : 1u, VK_IMAGE_VIEW_TYPE_1D };
|
||||||
case DxbcResourceDim::Texture1DArr: return { spv::Dim1D, 1, 0, isUav ? 2u : 1u, 1u, VK_IMAGE_VIEW_TYPE_1D_ARRAY };
|
case DxbcResourceDim::Texture1DArr: return { spv::Dim1D, 1, 0, isUav ? 2u : 1u, VK_IMAGE_VIEW_TYPE_1D_ARRAY };
|
||||||
case DxbcResourceDim::Texture2D: return { spv::Dim2D, 0, 0, isUav ? 2u : 1u, 0u, VK_IMAGE_VIEW_TYPE_2D };
|
case DxbcResourceDim::Texture2D: return { spv::Dim2D, 0, 0, isUav ? 2u : 1u, VK_IMAGE_VIEW_TYPE_2D };
|
||||||
case DxbcResourceDim::Texture2DArr: return { spv::Dim2D, 1, 0, isUav ? 2u : 1u, 1u, VK_IMAGE_VIEW_TYPE_2D_ARRAY };
|
case DxbcResourceDim::Texture2DArr: return { spv::Dim2D, 1, 0, isUav ? 2u : 1u, VK_IMAGE_VIEW_TYPE_2D_ARRAY };
|
||||||
case DxbcResourceDim::Texture2DMs: return { spv::Dim2D, 0, 1, isUav ? 2u : 1u, 0u, VK_IMAGE_VIEW_TYPE_2D };
|
case DxbcResourceDim::Texture2DMs: return { spv::Dim2D, 0, 1, isUav ? 2u : 1u, VK_IMAGE_VIEW_TYPE_2D };
|
||||||
case DxbcResourceDim::Texture2DMsArr: return { spv::Dim2D, 1, 1, isUav ? 2u : 1u, 1u, VK_IMAGE_VIEW_TYPE_2D_ARRAY };
|
case DxbcResourceDim::Texture2DMsArr: return { spv::Dim2D, 1, 1, isUav ? 2u : 1u, VK_IMAGE_VIEW_TYPE_2D_ARRAY };
|
||||||
case DxbcResourceDim::Texture3D: return { spv::Dim3D, 0, 0, isUav ? 2u : 1u, 0u, VK_IMAGE_VIEW_TYPE_3D };
|
case DxbcResourceDim::Texture3D: return { spv::Dim3D, 0, 0, isUav ? 2u : 1u, VK_IMAGE_VIEW_TYPE_3D };
|
||||||
case DxbcResourceDim::TextureCube: return { spv::DimCube, 1, 0, isUav ? 2u : 1u, 0u, VK_IMAGE_VIEW_TYPE_CUBE_ARRAY };
|
case DxbcResourceDim::TextureCube: return { spv::DimCube, 0, 0, isUav ? 2u : 1u, VK_IMAGE_VIEW_TYPE_CUBE };
|
||||||
case DxbcResourceDim::TextureCubeArr: return { spv::DimCube, 1, 0, isUav ? 2u : 1u, 1u, VK_IMAGE_VIEW_TYPE_CUBE_ARRAY };
|
case DxbcResourceDim::TextureCubeArr: return { spv::DimCube, 1, 0, isUav ? 2u : 1u, VK_IMAGE_VIEW_TYPE_CUBE_ARRAY };
|
||||||
default: throw DxvkError(str::format("DxbcCompiler: Unsupported resource type: ", resourceType));
|
default: throw DxvkError(str::format("DxbcCompiler: Unsupported resource type: ", resourceType));
|
||||||
}
|
}
|
||||||
}();
|
}();
|
||||||
|
|
||||||
if (typeInfo.dim == spv::Dim2D && m_options.test(DxbcOption::ForceTex2DArray)) {
|
|
||||||
typeInfo.array = 1;
|
|
||||||
typeInfo.vtype = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
|
|
||||||
}
|
|
||||||
|
|
||||||
return typeInfo;
|
return typeInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,6 +96,34 @@ namespace dxvk {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Specialization constant properties
|
||||||
|
*
|
||||||
|
* Stores the name, data type and initial
|
||||||
|
* value of a specialization constant.
|
||||||
|
*/
|
||||||
|
struct DxbcSpecConstant {
|
||||||
|
DxbcScalarType ctype;
|
||||||
|
uint32_t ccount;
|
||||||
|
uint32_t value;
|
||||||
|
const char* name;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Helper struct for conditional execution
|
||||||
|
*
|
||||||
|
* Stores a set of labels required to implement either
|
||||||
|
* an if-then block or an if-then-else block. This is
|
||||||
|
* not used to implement control flow instructions.
|
||||||
|
*/
|
||||||
|
struct DxbcConditional {
|
||||||
|
uint32_t labelIf = 0;
|
||||||
|
uint32_t labelElse = 0;
|
||||||
|
uint32_t labelEnd = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Vertex shader-specific structure
|
* \brief Vertex shader-specific structure
|
||||||
*/
|
*/
|
||||||
@ -120,6 +148,7 @@ namespace dxvk {
|
|||||||
|
|
||||||
uint32_t builtinLayer = 0;
|
uint32_t builtinLayer = 0;
|
||||||
uint32_t builtinViewportId = 0;
|
uint32_t builtinViewportId = 0;
|
||||||
|
uint32_t builtinInvocationId = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -136,6 +165,8 @@ namespace dxvk {
|
|||||||
uint32_t builtinSampleMaskIn = 0;
|
uint32_t builtinSampleMaskIn = 0;
|
||||||
uint32_t builtinSampleMaskOut = 0;
|
uint32_t builtinSampleMaskOut = 0;
|
||||||
uint32_t builtinLayer = 0;
|
uint32_t builtinLayer = 0;
|
||||||
|
|
||||||
|
uint32_t killState = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -244,10 +275,11 @@ namespace dxvk {
|
|||||||
|
|
||||||
|
|
||||||
struct DxbcCfgBlockIf {
|
struct DxbcCfgBlockIf {
|
||||||
|
uint32_t ztestId;
|
||||||
uint32_t labelIf;
|
uint32_t labelIf;
|
||||||
uint32_t labelElse;
|
uint32_t labelElse;
|
||||||
uint32_t labelEnd;
|
uint32_t labelEnd;
|
||||||
bool hadElse;
|
size_t headerPtr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -382,6 +414,13 @@ namespace dxvk {
|
|||||||
// currently active if-else blocks and loops.
|
// currently active if-else blocks and loops.
|
||||||
std::vector<DxbcCfgBlock> m_controlFlowBlocks;
|
std::vector<DxbcCfgBlock> m_controlFlowBlocks;
|
||||||
|
|
||||||
|
///////////////////////////////////////////////
|
||||||
|
// Specialization constants. These are defined
|
||||||
|
// as needed by the getSpecConstant method.
|
||||||
|
std::array<DxbcRegisterValue,
|
||||||
|
uint32_t(DxvkSpecConstantId::SpecConstantIdMax) -
|
||||||
|
uint32_t(DxvkSpecConstantId::SpecConstantIdMin) + 1> m_specConstants;
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////
|
||||||
// Array of input values. Since v# registers are indexable
|
// Array of input values. Since v# registers are indexable
|
||||||
// in DXBC, we need to copy them into an array first.
|
// in DXBC, we need to copy them into an array first.
|
||||||
@ -513,6 +552,9 @@ namespace dxvk {
|
|||||||
void emitDclThreadGroup(
|
void emitDclThreadGroup(
|
||||||
const DxbcShaderInstruction& ins);
|
const DxbcShaderInstruction& ins);
|
||||||
|
|
||||||
|
void emitDclGsInstanceCount(
|
||||||
|
const DxbcShaderInstruction& ins);
|
||||||
|
|
||||||
uint32_t emitDclUavCounter(
|
uint32_t emitDclUavCounter(
|
||||||
uint32_t regId);
|
uint32_t regId);
|
||||||
|
|
||||||
@ -843,6 +885,14 @@ namespace dxvk {
|
|||||||
const DxbcRegister& reg,
|
const DxbcRegister& reg,
|
||||||
DxbcRegisterValue value);
|
DxbcRegisterValue value);
|
||||||
|
|
||||||
|
////////////////////////////////////////
|
||||||
|
// Spec constant declaration and access
|
||||||
|
DxbcRegisterValue getSpecConstant(
|
||||||
|
DxvkSpecConstantId specId);
|
||||||
|
|
||||||
|
DxbcSpecConstant getSpecConstantProperties(
|
||||||
|
DxvkSpecConstantId specId);
|
||||||
|
|
||||||
////////////////////////////
|
////////////////////////////
|
||||||
// Input/output preparation
|
// Input/output preparation
|
||||||
void emitInputSetup();
|
void emitInputSetup();
|
||||||
@ -906,6 +956,11 @@ namespace dxvk {
|
|||||||
DxbcSystemValue sv,
|
DxbcSystemValue sv,
|
||||||
uint32_t srcArray);
|
uint32_t srcArray);
|
||||||
|
|
||||||
|
///////////////////////////////
|
||||||
|
// Some state checking methods
|
||||||
|
uint32_t emitUavWriteTest(
|
||||||
|
const DxbcBufferInfo& uav);
|
||||||
|
|
||||||
//////////////////////////////////////
|
//////////////////////////////////////
|
||||||
// Common function definition methods
|
// Common function definition methods
|
||||||
void emitInit();
|
void emitInit();
|
||||||
|
@ -60,7 +60,6 @@ namespace dxvk {
|
|||||||
uint32_t array = 0;
|
uint32_t array = 0;
|
||||||
uint32_t ms = 0;
|
uint32_t ms = 0;
|
||||||
uint32_t sampled = 0;
|
uint32_t sampled = 0;
|
||||||
uint32_t layered = 0;
|
|
||||||
VkImageViewType vtype = VK_IMAGE_VIEW_TYPE_MAX_ENUM;
|
VkImageViewType vtype = VK_IMAGE_VIEW_TYPE_MAX_ENUM;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -999,7 +999,9 @@ namespace dxvk {
|
|||||||
{ DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
|
{ DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
|
||||||
} },
|
} },
|
||||||
/* DclGsInstanceCount */
|
/* DclGsInstanceCount */
|
||||||
{ },
|
{ 1, DxbcInstClass::Declaration, {
|
||||||
|
{ DxbcOperandKind::Imm32, DxbcScalarType::Uint32 },
|
||||||
|
} },
|
||||||
}};
|
}};
|
||||||
|
|
||||||
|
|
||||||
|
@ -54,13 +54,14 @@ namespace dxvk {
|
|||||||
m_isgnChunk, m_osgnChunk,
|
m_isgnChunk, m_osgnChunk,
|
||||||
analysisInfo);
|
analysisInfo);
|
||||||
|
|
||||||
|
this->runAnalyzer(analyzer, m_shexChunk->slice());
|
||||||
|
|
||||||
DxbcCompiler compiler(
|
DxbcCompiler compiler(
|
||||||
fileName, options,
|
fileName, options,
|
||||||
m_shexChunk->version(),
|
m_shexChunk->version(),
|
||||||
m_isgnChunk, m_osgnChunk,
|
m_isgnChunk, m_osgnChunk,
|
||||||
analysisInfo);
|
analysisInfo);
|
||||||
|
|
||||||
this->runAnalyzer(analyzer, m_shexChunk->slice());
|
|
||||||
this->runCompiler(compiler, m_shexChunk->slice());
|
this->runCompiler(compiler, m_shexChunk->slice());
|
||||||
|
|
||||||
return compiler.finalize();
|
return compiler.finalize();
|
||||||
|
@ -5,8 +5,7 @@
|
|||||||
namespace dxvk {
|
namespace dxvk {
|
||||||
|
|
||||||
const static std::unordered_map<std::string, DxbcOptions> g_dxbcAppOptions = {{
|
const static std::unordered_map<std::string, DxbcOptions> g_dxbcAppOptions = {{
|
||||||
{ "Dishonored2.exe", DxbcOptions(DxbcOption::ForceTex2DArray) },
|
|
||||||
{ "ManiaPlanet.exe", DxbcOptions(DxbcOption::ForceTex2DArray) },
|
|
||||||
}};
|
}};
|
||||||
|
|
||||||
|
|
||||||
@ -36,6 +35,7 @@ namespace dxvk {
|
|||||||
if (devFeatures.shaderStorageImageReadWithoutFormat)
|
if (devFeatures.shaderStorageImageReadWithoutFormat)
|
||||||
flags.set(DxbcOption::UseStorageImageReadWithoutFormat);
|
flags.set(DxbcOption::UseStorageImageReadWithoutFormat);
|
||||||
|
|
||||||
|
flags.set(DxbcOption::DeferKill);
|
||||||
return flags;
|
return flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,10 +18,10 @@ namespace dxvk {
|
|||||||
/// Workaround for bugs in older Nvidia drivers.
|
/// Workaround for bugs in older Nvidia drivers.
|
||||||
UseSimpleMinMaxClamp,
|
UseSimpleMinMaxClamp,
|
||||||
|
|
||||||
/// Enforces the use of array views even when dealing
|
/// Defer kill operation to the end of the shader.
|
||||||
/// with non-array texture types. Some games do not
|
/// Fixes derivatives that are undefined due to
|
||||||
/// bind the correct texture type to the pipeline.
|
/// non-uniform control flow in fragment shaders.
|
||||||
ForceTex2DArray,
|
DeferKill,
|
||||||
};
|
};
|
||||||
|
|
||||||
using DxbcOptions = Flags<DxbcOption>;
|
using DxbcOptions = Flags<DxbcOption>;
|
||||||
|
@ -36,6 +36,7 @@ namespace dxvk {
|
|||||||
|| riid == __uuidof(IDXGIObject)
|
|| riid == __uuidof(IDXGIObject)
|
||||||
|| riid == __uuidof(IDXGIAdapter)
|
|| riid == __uuidof(IDXGIAdapter)
|
||||||
|| riid == __uuidof(IDXGIAdapter1)
|
|| riid == __uuidof(IDXGIAdapter1)
|
||||||
|
|| riid == __uuidof(IDXGIAdapter2)
|
||||||
|| riid == __uuidof(IDXGIVkAdapter)) {
|
|| riid == __uuidof(IDXGIVkAdapter)) {
|
||||||
*ppvObject = ref(this);
|
*ppvObject = ref(this);
|
||||||
return S_OK;
|
return S_OK;
|
||||||
@ -96,23 +97,20 @@ namespace dxvk {
|
|||||||
if (pDesc == nullptr)
|
if (pDesc == nullptr)
|
||||||
return DXGI_ERROR_INVALID_CALL;
|
return DXGI_ERROR_INVALID_CALL;
|
||||||
|
|
||||||
DXGI_ADAPTER_DESC1 desc1;
|
DXGI_ADAPTER_DESC2 desc;
|
||||||
HRESULT hr = this->GetDesc1(&desc1);
|
HRESULT hr = GetDesc2(&desc);
|
||||||
|
|
||||||
if (SUCCEEDED(hr)) {
|
if (SUCCEEDED(hr)) {
|
||||||
std::memcpy(
|
std::memcpy(pDesc->Description, desc.Description, sizeof(pDesc->Description));
|
||||||
pDesc->Description,
|
|
||||||
desc1.Description,
|
|
||||||
sizeof(pDesc->Description));
|
|
||||||
|
|
||||||
pDesc->VendorId = desc1.VendorId;
|
pDesc->VendorId = desc.VendorId;
|
||||||
pDesc->DeviceId = desc1.DeviceId;
|
pDesc->DeviceId = desc.DeviceId;
|
||||||
pDesc->SubSysId = desc1.SubSysId;
|
pDesc->SubSysId = desc.SubSysId;
|
||||||
pDesc->Revision = desc1.Revision;
|
pDesc->Revision = desc.Revision;
|
||||||
pDesc->DedicatedVideoMemory = desc1.DedicatedVideoMemory;
|
pDesc->DedicatedVideoMemory = desc.DedicatedVideoMemory;
|
||||||
pDesc->DedicatedSystemMemory = desc1.DedicatedSystemMemory;
|
pDesc->DedicatedSystemMemory = desc.DedicatedSystemMemory;
|
||||||
pDesc->SharedSystemMemory = desc1.SharedSystemMemory;
|
pDesc->SharedSystemMemory = desc.SharedSystemMemory;
|
||||||
pDesc->AdapterLuid = desc1.AdapterLuid;
|
pDesc->AdapterLuid = desc.AdapterLuid;
|
||||||
}
|
}
|
||||||
|
|
||||||
return hr;
|
return hr;
|
||||||
@ -122,6 +120,31 @@ namespace dxvk {
|
|||||||
HRESULT STDMETHODCALLTYPE DxgiAdapter::GetDesc1(DXGI_ADAPTER_DESC1* pDesc) {
|
HRESULT STDMETHODCALLTYPE DxgiAdapter::GetDesc1(DXGI_ADAPTER_DESC1* pDesc) {
|
||||||
if (pDesc == nullptr)
|
if (pDesc == nullptr)
|
||||||
return DXGI_ERROR_INVALID_CALL;
|
return DXGI_ERROR_INVALID_CALL;
|
||||||
|
|
||||||
|
DXGI_ADAPTER_DESC2 desc;
|
||||||
|
HRESULT hr = GetDesc2(&desc);
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr)) {
|
||||||
|
std::memcpy(pDesc->Description, desc.Description, sizeof(pDesc->Description));
|
||||||
|
|
||||||
|
pDesc->VendorId = desc.VendorId;
|
||||||
|
pDesc->DeviceId = desc.DeviceId;
|
||||||
|
pDesc->SubSysId = desc.SubSysId;
|
||||||
|
pDesc->Revision = desc.Revision;
|
||||||
|
pDesc->DedicatedVideoMemory = desc.DedicatedVideoMemory;
|
||||||
|
pDesc->DedicatedSystemMemory = desc.DedicatedSystemMemory;
|
||||||
|
pDesc->SharedSystemMemory = desc.SharedSystemMemory;
|
||||||
|
pDesc->AdapterLuid = desc.AdapterLuid;
|
||||||
|
pDesc->Flags = desc.Flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
HRESULT STDMETHODCALLTYPE DxgiAdapter::GetDesc2(DXGI_ADAPTER_DESC2* pDesc) {
|
||||||
|
if (pDesc == nullptr)
|
||||||
|
return DXGI_ERROR_INVALID_CALL;
|
||||||
|
|
||||||
auto deviceProp = m_adapter->deviceProperties();
|
auto deviceProp = m_adapter->deviceProperties();
|
||||||
auto memoryProp = m_adapter->memoryProperties();
|
auto memoryProp = m_adapter->memoryProperties();
|
||||||
@ -158,20 +181,22 @@ namespace dxvk {
|
|||||||
#ifndef _WIN64
|
#ifndef _WIN64
|
||||||
// The value returned by DXGI is a 32-bit value
|
// The value returned by DXGI is a 32-bit value
|
||||||
// on 32-bit platforms, so we need to clamp it
|
// on 32-bit platforms, so we need to clamp it
|
||||||
VkDeviceSize maxMemory = 0xF0000000;
|
VkDeviceSize maxMemory = 0xC0000000;
|
||||||
deviceMemory = std::min(deviceMemory, maxMemory);
|
deviceMemory = std::min(deviceMemory, maxMemory);
|
||||||
sharedMemory = std::min(sharedMemory, maxMemory);
|
sharedMemory = std::min(sharedMemory, maxMemory);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
pDesc->VendorId = deviceProp.vendorID;
|
pDesc->VendorId = deviceProp.vendorID;
|
||||||
pDesc->DeviceId = deviceProp.deviceID;
|
pDesc->DeviceId = deviceProp.deviceID;
|
||||||
pDesc->SubSysId = 0;
|
pDesc->SubSysId = 0;
|
||||||
pDesc->Revision = 0;
|
pDesc->Revision = 0;
|
||||||
pDesc->DedicatedVideoMemory = deviceMemory;
|
pDesc->DedicatedVideoMemory = deviceMemory;
|
||||||
pDesc->DedicatedSystemMemory = 0;
|
pDesc->DedicatedSystemMemory = 0;
|
||||||
pDesc->SharedSystemMemory = sharedMemory;
|
pDesc->SharedSystemMemory = sharedMemory;
|
||||||
pDesc->AdapterLuid = LUID { 0, 0 }; // TODO implement
|
pDesc->AdapterLuid = LUID { 0, 0 }; // TODO implement
|
||||||
pDesc->Flags = 0;
|
pDesc->Flags = 0;
|
||||||
|
pDesc->GraphicsPreemptionGranularity = DXGI_GRAPHICS_PREEMPTION_DMA_BUFFER_BOUNDARY;
|
||||||
|
pDesc->ComputePreemptionGranularity = DXGI_COMPUTE_PREEMPTION_DMA_BUFFER_BOUNDARY;
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,6 +43,9 @@ namespace dxvk {
|
|||||||
HRESULT STDMETHODCALLTYPE GetDesc1(
|
HRESULT STDMETHODCALLTYPE GetDesc1(
|
||||||
DXGI_ADAPTER_DESC1* pDesc) final;
|
DXGI_ADAPTER_DESC1* pDesc) final;
|
||||||
|
|
||||||
|
HRESULT STDMETHODCALLTYPE GetDesc2(
|
||||||
|
DXGI_ADAPTER_DESC2* pDesc) final;
|
||||||
|
|
||||||
Rc<DxvkAdapter> STDMETHODCALLTYPE GetDXVKAdapter() final;
|
Rc<DxvkAdapter> STDMETHODCALLTYPE GetDXVKAdapter() final;
|
||||||
|
|
||||||
HRESULT STDMETHODCALLTYPE CreateDevice(
|
HRESULT STDMETHODCALLTYPE CreateDevice(
|
||||||
|
@ -125,7 +125,7 @@ namespace dxvk {
|
|||||||
IDXGIResource* const* ppResources,
|
IDXGIResource* const* ppResources,
|
||||||
DXGI_OFFER_RESOURCE_PRIORITY Priority) {
|
DXGI_OFFER_RESOURCE_PRIORITY Priority) {
|
||||||
|
|
||||||
Logger::err("DxgiDevice::OfferResources: not implemented");
|
Logger::err("DxgiDevice::OfferResources: Not implemented");
|
||||||
return DXGI_ERROR_UNSUPPORTED;
|
return DXGI_ERROR_UNSUPPORTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -134,13 +134,13 @@ namespace dxvk {
|
|||||||
UINT NumResources,
|
UINT NumResources,
|
||||||
IDXGIResource* const* ppResources,
|
IDXGIResource* const* ppResources,
|
||||||
BOOL* pDiscarded) {
|
BOOL* pDiscarded) {
|
||||||
Logger::err("DxgiDevice::ReclaimResources: not implemented");
|
Logger::err("DxgiDevice::ReclaimResources: Not implemented");
|
||||||
return DXGI_ERROR_UNSUPPORTED;
|
return DXGI_ERROR_UNSUPPORTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
HRESULT STDMETHODCALLTYPE DxgiDevice::EnqueueSetEvent(HANDLE hEvent) {
|
HRESULT STDMETHODCALLTYPE DxgiDevice::EnqueueSetEvent(HANDLE hEvent) {
|
||||||
Logger::err("DxgiDevice::EnqueueSetEvent: not implemented");
|
Logger::err("DxgiDevice::EnqueueSetEvent: Not implemented");
|
||||||
return DXGI_ERROR_UNSUPPORTED;
|
return DXGI_ERROR_UNSUPPORTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,7 +22,8 @@ namespace dxvk {
|
|||||||
if (riid == __uuidof(IUnknown)
|
if (riid == __uuidof(IUnknown)
|
||||||
|| riid == __uuidof(IDXGIObject)
|
|| riid == __uuidof(IDXGIObject)
|
||||||
|| riid == __uuidof(IDXGIFactory)
|
|| riid == __uuidof(IDXGIFactory)
|
||||||
|| riid == __uuidof(IDXGIFactory1)) {
|
|| riid == __uuidof(IDXGIFactory1)
|
||||||
|
|| riid == __uuidof(IDXGIFactory2)) {
|
||||||
*ppvObject = ref(this);
|
*ppvObject = ref(this);
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
@ -41,6 +42,12 @@ namespace dxvk {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BOOL STDMETHODCALLTYPE DxgiFactory::IsWindowedStereoEnabled() {
|
||||||
|
// We don't support Stereo 3D at the moment
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
HRESULT STDMETHODCALLTYPE DxgiFactory::CreateSoftwareAdapter(
|
HRESULT STDMETHODCALLTYPE DxgiFactory::CreateSoftwareAdapter(
|
||||||
HMODULE Module,
|
HMODULE Module,
|
||||||
IDXGIAdapter** ppAdapter) {
|
IDXGIAdapter** ppAdapter) {
|
||||||
@ -58,16 +65,67 @@ namespace dxvk {
|
|||||||
IUnknown* pDevice,
|
IUnknown* pDevice,
|
||||||
DXGI_SWAP_CHAIN_DESC* pDesc,
|
DXGI_SWAP_CHAIN_DESC* pDesc,
|
||||||
IDXGISwapChain** ppSwapChain) {
|
IDXGISwapChain** ppSwapChain) {
|
||||||
|
if (ppSwapChain == nullptr || pDesc == nullptr || pDevice == nullptr)
|
||||||
|
return DXGI_ERROR_INVALID_CALL;
|
||||||
|
|
||||||
|
DXGI_SWAP_CHAIN_DESC1 desc;
|
||||||
|
desc.Width = pDesc->BufferDesc.Width;
|
||||||
|
desc.Height = pDesc->BufferDesc.Height;
|
||||||
|
desc.Format = pDesc->BufferDesc.Format;
|
||||||
|
desc.Stereo = FALSE;
|
||||||
|
desc.SampleDesc = pDesc->SampleDesc;
|
||||||
|
desc.BufferUsage = pDesc->BufferUsage;
|
||||||
|
desc.BufferCount = pDesc->BufferCount;
|
||||||
|
desc.Scaling = DXGI_SCALING_STRETCH;
|
||||||
|
desc.SwapEffect = pDesc->SwapEffect;
|
||||||
|
desc.AlphaMode = DXGI_ALPHA_MODE_IGNORE;
|
||||||
|
desc.Flags = pDesc->Flags;
|
||||||
|
|
||||||
|
DXGI_SWAP_CHAIN_FULLSCREEN_DESC descFs;
|
||||||
|
descFs.RefreshRate = pDesc->BufferDesc.RefreshRate;
|
||||||
|
descFs.ScanlineOrdering = pDesc->BufferDesc.ScanlineOrdering;
|
||||||
|
descFs.Scaling = pDesc->BufferDesc.Scaling;
|
||||||
|
descFs.Windowed = pDesc->Windowed;
|
||||||
|
|
||||||
|
IDXGISwapChain1* swapChain = nullptr;
|
||||||
|
HRESULT hr = CreateSwapChainForHwnd(
|
||||||
|
pDevice, pDesc->OutputWindow,
|
||||||
|
&desc, &descFs, nullptr,
|
||||||
|
&swapChain);
|
||||||
|
|
||||||
|
*ppSwapChain = swapChain;
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
HRESULT STDMETHODCALLTYPE DxgiFactory::CreateSwapChainForHwnd(
|
||||||
|
IUnknown* pDevice,
|
||||||
|
HWND hWnd,
|
||||||
|
const DXGI_SWAP_CHAIN_DESC1* pDesc,
|
||||||
|
const DXGI_SWAP_CHAIN_FULLSCREEN_DESC* pFullscreenDesc,
|
||||||
|
IDXGIOutput* pRestrictToOutput,
|
||||||
|
IDXGISwapChain1** ppSwapChain) {
|
||||||
InitReturnPtr(ppSwapChain);
|
InitReturnPtr(ppSwapChain);
|
||||||
|
|
||||||
if (ppSwapChain == nullptr || pDesc == nullptr || pDevice == NULL)
|
if (ppSwapChain == nullptr || pDesc == nullptr || hWnd == nullptr || pDevice == nullptr)
|
||||||
return DXGI_ERROR_INVALID_CALL;
|
return DXGI_ERROR_INVALID_CALL;
|
||||||
|
|
||||||
if (pDesc->OutputWindow == nullptr)
|
// If necessary, set up a default set of
|
||||||
return DXGI_ERROR_INVALID_CALL;
|
// fullscreen parameters for the swap chain
|
||||||
|
DXGI_SWAP_CHAIN_FULLSCREEN_DESC fullscreenDesc;
|
||||||
|
|
||||||
|
if (pFullscreenDesc != nullptr) {
|
||||||
|
fullscreenDesc = *pFullscreenDesc;
|
||||||
|
} else {
|
||||||
|
fullscreenDesc.RefreshRate = { 0, 0 };
|
||||||
|
fullscreenDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
|
||||||
|
fullscreenDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
|
||||||
|
fullscreenDesc.Windowed = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
*ppSwapChain = ref(new DxgiSwapChain(this, pDevice, pDesc));
|
*ppSwapChain = ref(new DxgiSwapChain(this,
|
||||||
|
pDevice, hWnd, pDesc, &fullscreenDesc));
|
||||||
return S_OK;
|
return S_OK;
|
||||||
} catch (const DxvkError& e) {
|
} catch (const DxvkError& e) {
|
||||||
Logger::err(e.message());
|
Logger::err(e.message());
|
||||||
@ -76,6 +134,31 @@ namespace dxvk {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
HRESULT STDMETHODCALLTYPE DxgiFactory::CreateSwapChainForCoreWindow(
|
||||||
|
IUnknown* pDevice,
|
||||||
|
IUnknown* pWindow,
|
||||||
|
const DXGI_SWAP_CHAIN_DESC1* pDesc,
|
||||||
|
IDXGIOutput* pRestrictToOutput,
|
||||||
|
IDXGISwapChain1** ppSwapChain) {
|
||||||
|
InitReturnPtr(ppSwapChain);
|
||||||
|
|
||||||
|
Logger::err("DxgiFactory::CreateSwapChainForCoreWindow: Not implemented");
|
||||||
|
return E_NOTIMPL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
HRESULT STDMETHODCALLTYPE DxgiFactory::CreateSwapChainForComposition(
|
||||||
|
IUnknown* pDevice,
|
||||||
|
const DXGI_SWAP_CHAIN_DESC1* pDesc,
|
||||||
|
IDXGIOutput* pRestrictToOutput,
|
||||||
|
IDXGISwapChain1** ppSwapChain) {
|
||||||
|
InitReturnPtr(ppSwapChain);
|
||||||
|
|
||||||
|
Logger::err("DxgiFactory::CreateSwapChainForComposition: Not implemented");
|
||||||
|
return E_NOTIMPL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
HRESULT STDMETHODCALLTYPE DxgiFactory::EnumAdapters(
|
HRESULT STDMETHODCALLTYPE DxgiFactory::EnumAdapters(
|
||||||
UINT Adapter,
|
UINT Adapter,
|
||||||
IDXGIAdapter** ppAdapter) {
|
IDXGIAdapter** ppAdapter) {
|
||||||
@ -117,6 +200,14 @@ namespace dxvk {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
HRESULT STDMETHODCALLTYPE DxgiFactory::GetSharedResourceAdapterLuid(
|
||||||
|
HANDLE hResource,
|
||||||
|
LUID* pLuid) {
|
||||||
|
Logger::err("DxgiFactory::GetSharedResourceAdapterLuid: Not implemented");
|
||||||
|
return E_NOTIMPL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
HRESULT STDMETHODCALLTYPE DxgiFactory::MakeWindowAssociation(HWND WindowHandle, UINT Flags) {
|
HRESULT STDMETHODCALLTYPE DxgiFactory::MakeWindowAssociation(HWND WindowHandle, UINT Flags) {
|
||||||
Logger::warn("DXGI: MakeWindowAssociation: Ignoring flags");
|
Logger::warn("DXGI: MakeWindowAssociation: Ignoring flags");
|
||||||
m_associatedWindow = WindowHandle;
|
m_associatedWindow = WindowHandle;
|
||||||
@ -129,4 +220,50 @@ namespace dxvk {
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
HRESULT STDMETHODCALLTYPE DxgiFactory::RegisterOcclusionStatusWindow(
|
||||||
|
HWND WindowHandle,
|
||||||
|
UINT wMsg,
|
||||||
|
DWORD* pdwCookie) {
|
||||||
|
Logger::err("DxgiFactory::RegisterOcclusionStatusWindow: Not implemented");
|
||||||
|
return E_NOTIMPL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
HRESULT STDMETHODCALLTYPE DxgiFactory::RegisterStereoStatusEvent(
|
||||||
|
HANDLE hEvent,
|
||||||
|
DWORD* pdwCookie) {
|
||||||
|
Logger::err("DxgiFactory::RegisterStereoStatusEvent: Not implemented");
|
||||||
|
return E_NOTIMPL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
HRESULT STDMETHODCALLTYPE DxgiFactory::RegisterStereoStatusWindow(
|
||||||
|
HWND WindowHandle,
|
||||||
|
UINT wMsg,
|
||||||
|
DWORD* pdwCookie) {
|
||||||
|
Logger::err("DxgiFactory::RegisterStereoStatusWindow: Not implemented");
|
||||||
|
return E_NOTIMPL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
HRESULT STDMETHODCALLTYPE DxgiFactory::RegisterOcclusionStatusEvent(
|
||||||
|
HANDLE hEvent,
|
||||||
|
DWORD* pdwCookie) {
|
||||||
|
Logger::err("DxgiFactory::RegisterOcclusionStatusEvent: Not implemented");
|
||||||
|
return E_NOTIMPL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void STDMETHODCALLTYPE DxgiFactory::UnregisterStereoStatus(
|
||||||
|
DWORD dwCookie) {
|
||||||
|
Logger::err("DxgiFactory::UnregisterStereoStatus: Not implemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void STDMETHODCALLTYPE DxgiFactory::UnregisterOcclusionStatus(
|
||||||
|
DWORD dwCookie) {
|
||||||
|
Logger::err("DxgiFactory::UnregisterOcclusionStatus: Not implemented");
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
namespace dxvk {
|
namespace dxvk {
|
||||||
|
|
||||||
class DxgiFactory : public DxgiObject<IDXGIFactory1> {
|
class DxgiFactory : public DxgiObject<IDXGIFactory2> {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
@ -23,6 +23,8 @@ namespace dxvk {
|
|||||||
REFIID riid,
|
REFIID riid,
|
||||||
void** ppParent) final;
|
void** ppParent) final;
|
||||||
|
|
||||||
|
BOOL STDMETHODCALLTYPE IsWindowedStereoEnabled() final;
|
||||||
|
|
||||||
HRESULT STDMETHODCALLTYPE CreateSoftwareAdapter(
|
HRESULT STDMETHODCALLTYPE CreateSoftwareAdapter(
|
||||||
HMODULE Module,
|
HMODULE Module,
|
||||||
IDXGIAdapter** ppAdapter) final;
|
IDXGIAdapter** ppAdapter) final;
|
||||||
@ -32,6 +34,27 @@ namespace dxvk {
|
|||||||
DXGI_SWAP_CHAIN_DESC* pDesc,
|
DXGI_SWAP_CHAIN_DESC* pDesc,
|
||||||
IDXGISwapChain** ppSwapChain) final;
|
IDXGISwapChain** ppSwapChain) final;
|
||||||
|
|
||||||
|
HRESULT STDMETHODCALLTYPE CreateSwapChainForHwnd(
|
||||||
|
IUnknown* pDevice,
|
||||||
|
HWND hWnd,
|
||||||
|
const DXGI_SWAP_CHAIN_DESC1* pDesc,
|
||||||
|
const DXGI_SWAP_CHAIN_FULLSCREEN_DESC* pFullscreenDesc,
|
||||||
|
IDXGIOutput* pRestrictToOutput,
|
||||||
|
IDXGISwapChain1** ppSwapChain) final;
|
||||||
|
|
||||||
|
HRESULT STDMETHODCALLTYPE CreateSwapChainForCoreWindow(
|
||||||
|
IUnknown* pDevice,
|
||||||
|
IUnknown* pWindow,
|
||||||
|
const DXGI_SWAP_CHAIN_DESC1* pDesc,
|
||||||
|
IDXGIOutput* pRestrictToOutput,
|
||||||
|
IDXGISwapChain1** ppSwapChain) final;
|
||||||
|
|
||||||
|
HRESULT STDMETHODCALLTYPE CreateSwapChainForComposition(
|
||||||
|
IUnknown* pDevice,
|
||||||
|
const DXGI_SWAP_CHAIN_DESC1* pDesc,
|
||||||
|
IDXGIOutput* pRestrictToOutput,
|
||||||
|
IDXGISwapChain1** ppSwapChain) final;
|
||||||
|
|
||||||
HRESULT STDMETHODCALLTYPE EnumAdapters(
|
HRESULT STDMETHODCALLTYPE EnumAdapters(
|
||||||
UINT Adapter,
|
UINT Adapter,
|
||||||
IDXGIAdapter** ppAdapter) final;
|
IDXGIAdapter** ppAdapter) final;
|
||||||
@ -43,11 +66,39 @@ namespace dxvk {
|
|||||||
HRESULT STDMETHODCALLTYPE GetWindowAssociation(
|
HRESULT STDMETHODCALLTYPE GetWindowAssociation(
|
||||||
HWND* pWindowHandle) final;
|
HWND* pWindowHandle) final;
|
||||||
|
|
||||||
|
HRESULT STDMETHODCALLTYPE GetSharedResourceAdapterLuid(
|
||||||
|
HANDLE hResource,
|
||||||
|
LUID* pLuid) final;
|
||||||
|
|
||||||
HRESULT STDMETHODCALLTYPE MakeWindowAssociation(
|
HRESULT STDMETHODCALLTYPE MakeWindowAssociation(
|
||||||
HWND WindowHandle,
|
HWND WindowHandle,
|
||||||
UINT Flags) final;
|
UINT Flags) final;
|
||||||
|
|
||||||
BOOL STDMETHODCALLTYPE IsCurrent();
|
BOOL STDMETHODCALLTYPE IsCurrent() final;
|
||||||
|
|
||||||
|
HRESULT STDMETHODCALLTYPE RegisterOcclusionStatusWindow(
|
||||||
|
HWND WindowHandle,
|
||||||
|
UINT wMsg,
|
||||||
|
DWORD* pdwCookie) final;
|
||||||
|
|
||||||
|
HRESULT STDMETHODCALLTYPE RegisterStereoStatusEvent(
|
||||||
|
HANDLE hEvent,
|
||||||
|
DWORD* pdwCookie) final;
|
||||||
|
|
||||||
|
HRESULT STDMETHODCALLTYPE RegisterStereoStatusWindow(
|
||||||
|
HWND WindowHandle,
|
||||||
|
UINT wMsg,
|
||||||
|
DWORD* pdwCookie) final;
|
||||||
|
|
||||||
|
HRESULT STDMETHODCALLTYPE RegisterOcclusionStatusEvent(
|
||||||
|
HANDLE hEvent,
|
||||||
|
DWORD* pdwCookie) final;
|
||||||
|
|
||||||
|
void STDMETHODCALLTYPE UnregisterStereoStatus(
|
||||||
|
DWORD dwCookie) final;
|
||||||
|
|
||||||
|
void STDMETHODCALLTYPE UnregisterOcclusionStatus(
|
||||||
|
DWORD dwCookie) final;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
@ -40,7 +40,7 @@ IDXGIVkDevice : public IDXGIDevice2 {
|
|||||||
* this interface.
|
* this interface.
|
||||||
*/
|
*/
|
||||||
MIDL_INTERFACE("907bf281-ea3c-43b4-a8e4-9f231107b4ff")
|
MIDL_INTERFACE("907bf281-ea3c-43b4-a8e4-9f231107b4ff")
|
||||||
IDXGIVkAdapter : public IDXGIAdapter1 {
|
IDXGIVkAdapter : public IDXGIAdapter2 {
|
||||||
static const GUID guid;
|
static const GUID guid;
|
||||||
|
|
||||||
virtual dxvk::Rc<dxvk::DxvkAdapter> STDMETHODCALLTYPE GetDXVKAdapter() = 0;
|
virtual dxvk::Rc<dxvk::DxvkAdapter> STDMETHODCALLTYPE GetDXVKAdapter() = 0;
|
||||||
@ -109,7 +109,7 @@ IDXGIVkPresenter : public IUnknown {
|
|||||||
* \returns \c S_OK on success
|
* \returns \c S_OK on success
|
||||||
*/
|
*/
|
||||||
virtual HRESULT STDMETHODCALLTYPE CreateSwapChainBackBuffer(
|
virtual HRESULT STDMETHODCALLTYPE CreateSwapChainBackBuffer(
|
||||||
const DXGI_SWAP_CHAIN_DESC* pSwapChainDesc,
|
const DXGI_SWAP_CHAIN_DESC1* pSwapChainDesc,
|
||||||
IDXGIVkBackBuffer** ppBackBuffer) = 0;
|
IDXGIVkBackBuffer** ppBackBuffer) = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -7,7 +7,8 @@ namespace dxvk {
|
|||||||
|
|
||||||
HRESULT createDxgiFactory(REFIID riid, void **ppFactory) {
|
HRESULT createDxgiFactory(REFIID riid, void **ppFactory) {
|
||||||
if (riid != __uuidof(IDXGIFactory)
|
if (riid != __uuidof(IDXGIFactory)
|
||||||
&& riid != __uuidof(IDXGIFactory1)) {
|
&& riid != __uuidof(IDXGIFactory1)
|
||||||
|
&& riid != __uuidof(IDXGIFactory2)) {
|
||||||
Logger::err("CreateDXGIFactory: Requested version of IDXGIFactory not supported");
|
Logger::err("CreateDXGIFactory: Requested version of IDXGIFactory not supported");
|
||||||
Logger::err(str::format(riid));
|
Logger::err(str::format(riid));
|
||||||
*ppFactory = nullptr;
|
*ppFactory = nullptr;
|
||||||
|
20
src/dxgi/dxgi_options.cpp
Normal file
20
src/dxgi/dxgi_options.cpp
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
#include "dxgi_options.h"
|
||||||
|
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
namespace dxvk {
|
||||||
|
|
||||||
|
const static std::unordered_map<std::string, DxgiOptions> g_dxgiAppOptions = {{
|
||||||
|
{ "Frostpunk.exe", DxgiOptions(DxgiOption::DeferSurfaceCreation) },
|
||||||
|
}};
|
||||||
|
|
||||||
|
|
||||||
|
DxgiOptions getDxgiAppOptions(const std::string& appName) {
|
||||||
|
auto appOptions = g_dxgiAppOptions.find(appName);
|
||||||
|
|
||||||
|
return appOptions != g_dxgiAppOptions.end()
|
||||||
|
? appOptions->second
|
||||||
|
: DxgiOptions();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
30
src/dxgi/dxgi_options.h
Normal file
30
src/dxgi/dxgi_options.h
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "dxgi_include.h"
|
||||||
|
|
||||||
|
namespace dxvk {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief DXGI options
|
||||||
|
*
|
||||||
|
* Per-app options that control the
|
||||||
|
* behaviour of some DXGI classes.
|
||||||
|
*/
|
||||||
|
enum class DxgiOption : uint64_t {
|
||||||
|
/// Defer surface creation until first present call. This
|
||||||
|
/// fixes issues with games that create multiple swap chains
|
||||||
|
/// for a single window that may interfere with each other.
|
||||||
|
DeferSurfaceCreation,
|
||||||
|
};
|
||||||
|
|
||||||
|
using DxgiOptions = Flags<DxgiOption>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Gets app-specific DXGI options
|
||||||
|
*
|
||||||
|
* \param [in] appName Application name
|
||||||
|
* \returns DXGI options for this application
|
||||||
|
*/
|
||||||
|
DxgiOptions getDxgiAppOptions(const std::string& appName);
|
||||||
|
|
||||||
|
}
|
@ -10,14 +10,16 @@ namespace dxvk {
|
|||||||
DxgiVkPresenter::DxgiVkPresenter(
|
DxgiVkPresenter::DxgiVkPresenter(
|
||||||
const Rc<DxvkDevice>& device,
|
const Rc<DxvkDevice>& device,
|
||||||
HWND window)
|
HWND window)
|
||||||
: m_device (device),
|
: m_window (window),
|
||||||
|
m_device (device),
|
||||||
m_context (device->createContext()) {
|
m_context (device->createContext()) {
|
||||||
|
|
||||||
// Create Vulkan surface for the window
|
// Some games don't work with deferred surface creation,
|
||||||
HINSTANCE instance = reinterpret_cast<HINSTANCE>(
|
// so we should default to initializing it immediately.
|
||||||
GetWindowLongPtr(window, GWLP_HINSTANCE));
|
DxgiOptions dxgiOptions = getDxgiAppOptions(env::getExeName());
|
||||||
|
|
||||||
m_surface = m_device->adapter()->createSurface(instance, window);
|
if (!dxgiOptions.test(DxgiOption::DeferSurfaceCreation))
|
||||||
|
m_surface = CreateSurface();
|
||||||
|
|
||||||
// Reset options for the swap chain itself. We will
|
// Reset options for the swap chain itself. We will
|
||||||
// create a swap chain object before presentation.
|
// create a swap chain object before presentation.
|
||||||
@ -275,27 +277,52 @@ namespace dxvk {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void DxgiVkPresenter::RecreateSwapchain(const DxvkSwapchainProperties* pOptions) {
|
void DxgiVkPresenter::SetGammaControl(
|
||||||
|
const DXGI_VK_GAMMA_CURVE* pGammaCurve) {
|
||||||
|
m_context->beginRecording(
|
||||||
|
m_device->createCommandList());
|
||||||
|
|
||||||
|
m_context->updateImage(m_gammaTexture,
|
||||||
|
VkImageSubresourceLayers { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 },
|
||||||
|
VkOffset3D { 0, 0, 0 },
|
||||||
|
VkExtent3D { DXGI_VK_GAMMA_CP_COUNT, 1, 1 },
|
||||||
|
pGammaCurve, 0, 0);
|
||||||
|
|
||||||
|
m_device->submitCommandList(
|
||||||
|
m_context->endRecording(),
|
||||||
|
nullptr, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void DxgiVkPresenter::RecreateSwapchain(DXGI_FORMAT Format, VkPresentModeKHR PresentMode, VkExtent2D WindowSize) {
|
||||||
|
if (m_surface == nullptr)
|
||||||
|
m_surface = CreateSurface();
|
||||||
|
|
||||||
|
DxvkSwapchainProperties options;
|
||||||
|
options.preferredSurfaceFormat = PickSurfaceFormat(Format);
|
||||||
|
options.preferredPresentMode = PickPresentMode(PresentMode);
|
||||||
|
options.preferredBufferSize = WindowSize;
|
||||||
|
|
||||||
const bool doRecreate =
|
const bool doRecreate =
|
||||||
pOptions->preferredSurfaceFormat.format != m_options.preferredSurfaceFormat.format
|
options.preferredSurfaceFormat.format != m_options.preferredSurfaceFormat.format
|
||||||
|| pOptions->preferredSurfaceFormat.colorSpace != m_options.preferredSurfaceFormat.colorSpace
|
|| options.preferredSurfaceFormat.colorSpace != m_options.preferredSurfaceFormat.colorSpace
|
||||||
|| pOptions->preferredPresentMode != m_options.preferredPresentMode
|
|| options.preferredPresentMode != m_options.preferredPresentMode
|
||||||
|| pOptions->preferredBufferSize.width != m_options.preferredBufferSize.width
|
|| options.preferredBufferSize.width != m_options.preferredBufferSize.width
|
||||||
|| pOptions->preferredBufferSize.height != m_options.preferredBufferSize.height;
|
|| options.preferredBufferSize.height != m_options.preferredBufferSize.height;
|
||||||
|
|
||||||
if (doRecreate) {
|
if (doRecreate) {
|
||||||
Logger::info(str::format(
|
Logger::info(str::format(
|
||||||
"DxgiVkPresenter: Recreating swap chain: ",
|
"DxgiVkPresenter: Recreating swap chain: ",
|
||||||
"\n Format: ", pOptions->preferredSurfaceFormat.format,
|
"\n Format: ", options.preferredSurfaceFormat.format,
|
||||||
"\n Present mode: ", pOptions->preferredPresentMode,
|
"\n Present mode: ", options.preferredPresentMode,
|
||||||
"\n Buffer size: ", pOptions->preferredBufferSize.width, "x", pOptions->preferredBufferSize.height));
|
"\n Buffer size: ", options.preferredBufferSize.width, "x", options.preferredBufferSize.height));
|
||||||
|
|
||||||
if (m_swapchain == nullptr)
|
if (m_swapchain == nullptr)
|
||||||
m_swapchain = m_device->createSwapchain(m_surface, *pOptions);
|
m_swapchain = m_device->createSwapchain(m_surface, options);
|
||||||
else
|
else
|
||||||
m_swapchain->changeProperties(*pOptions);
|
m_swapchain->changeProperties(options);
|
||||||
|
|
||||||
m_options = *pOptions;
|
m_options = options;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -339,20 +366,11 @@ namespace dxvk {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void DxgiVkPresenter::SetGammaControl(
|
Rc<DxvkSurface> DxgiVkPresenter::CreateSurface() {
|
||||||
const DXGI_VK_GAMMA_CURVE* pGammaCurve) {
|
HINSTANCE instance = reinterpret_cast<HINSTANCE>(
|
||||||
m_context->beginRecording(
|
GetWindowLongPtr(m_window, GWLP_HINSTANCE));
|
||||||
m_device->createCommandList());
|
|
||||||
|
|
||||||
m_context->updateImage(m_gammaTexture,
|
return m_device->adapter()->createSurface(instance, m_window);
|
||||||
VkImageSubresourceLayers { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 },
|
|
||||||
VkOffset3D { 0, 0, 0 },
|
|
||||||
VkExtent3D { DXGI_VK_GAMMA_CP_COUNT, 1, 1 },
|
|
||||||
pGammaCurve, 0, 0);
|
|
||||||
|
|
||||||
m_device->submitCommandList(
|
|
||||||
m_context->endRecording(),
|
|
||||||
nullptr, nullptr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
#include "../spirv/spirv_module.h"
|
#include "../spirv/spirv_module.h"
|
||||||
|
|
||||||
#include "dxgi_include.h"
|
#include "dxgi_options.h"
|
||||||
|
|
||||||
namespace dxvk {
|
namespace dxvk {
|
||||||
|
|
||||||
@ -100,28 +100,14 @@ namespace dxvk {
|
|||||||
* Only actually recreates the swap chain object
|
* Only actually recreates the swap chain object
|
||||||
* if any of the properties have changed. If no
|
* if any of the properties have changed. If no
|
||||||
* properties have changed, this is a no-op.
|
* properties have changed, this is a no-op.
|
||||||
* \param [in] options New swap chain options
|
* \param [in] Format New surface format
|
||||||
|
* \param [in] PresentMode Present mode
|
||||||
|
* \param [in] WindowSize Window size
|
||||||
*/
|
*/
|
||||||
void RecreateSwapchain(
|
void RecreateSwapchain(
|
||||||
const DxvkSwapchainProperties* pOptions);
|
DXGI_FORMAT Format,
|
||||||
|
VkPresentModeKHR PresentMode,
|
||||||
/**
|
VkExtent2D WindowSize);
|
||||||
* \brief Picks a surface format based on a DXGI format
|
|
||||||
*
|
|
||||||
* This will return a supported format that, if possible,
|
|
||||||
* has properties similar to those of the DXGI format.
|
|
||||||
* \param [in] fmt The DXGI format
|
|
||||||
* \returns The Vulkan format
|
|
||||||
*/
|
|
||||||
VkSurfaceFormatKHR PickSurfaceFormat(DXGI_FORMAT Fmt) const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Picks a supported present mode
|
|
||||||
*
|
|
||||||
* \param [in] preferred Preferred present mode
|
|
||||||
* \returns An actually supported present mode
|
|
||||||
*/
|
|
||||||
VkPresentModeKHR PickPresentMode(VkPresentModeKHR Preferred) const;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Sets gamma curve
|
* \brief Sets gamma curve
|
||||||
@ -142,6 +128,8 @@ namespace dxvk {
|
|||||||
GammaTex = 3,
|
GammaTex = 3,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
HWND m_window;
|
||||||
|
|
||||||
Rc<DxvkDevice> m_device;
|
Rc<DxvkDevice> m_device;
|
||||||
Rc<DxvkContext> m_context;
|
Rc<DxvkContext> m_context;
|
||||||
|
|
||||||
@ -164,6 +152,12 @@ namespace dxvk {
|
|||||||
DxvkBlendMode m_blendMode;
|
DxvkBlendMode m_blendMode;
|
||||||
DxvkSwapchainProperties m_options;
|
DxvkSwapchainProperties m_options;
|
||||||
|
|
||||||
|
VkSurfaceFormatKHR PickSurfaceFormat(DXGI_FORMAT Fmt) const;
|
||||||
|
|
||||||
|
VkPresentModeKHR PickPresentMode(VkPresentModeKHR Preferred) const;
|
||||||
|
|
||||||
|
Rc<DxvkSurface> CreateSurface();
|
||||||
|
|
||||||
Rc<DxvkSampler> CreateSampler(
|
Rc<DxvkSampler> CreateSampler(
|
||||||
VkFilter Filter,
|
VkFilter Filter,
|
||||||
VkSamplerAddressMode AddressMode);
|
VkSamplerAddressMode AddressMode);
|
||||||
|
@ -6,13 +6,16 @@
|
|||||||
namespace dxvk {
|
namespace dxvk {
|
||||||
|
|
||||||
DxgiSwapChain::DxgiSwapChain(
|
DxgiSwapChain::DxgiSwapChain(
|
||||||
DxgiFactory* factory,
|
DxgiFactory* pFactory,
|
||||||
IUnknown* pDevice,
|
IUnknown* pDevice,
|
||||||
DXGI_SWAP_CHAIN_DESC* pDesc)
|
HWND hWnd,
|
||||||
: m_factory (factory),
|
const DXGI_SWAP_CHAIN_DESC1* pDesc,
|
||||||
|
const DXGI_SWAP_CHAIN_FULLSCREEN_DESC* pFullscreenDesc)
|
||||||
|
: m_factory (pFactory),
|
||||||
|
m_window (hWnd),
|
||||||
m_desc (*pDesc),
|
m_desc (*pDesc),
|
||||||
|
m_descFs (*pFullscreenDesc),
|
||||||
m_monitor (nullptr) {
|
m_monitor (nullptr) {
|
||||||
|
|
||||||
// Retrieve a device pointer that allows us to
|
// Retrieve a device pointer that allows us to
|
||||||
// communicate with the underlying D3D device
|
// communicate with the underlying D3D device
|
||||||
if (FAILED(pDevice->QueryInterface(__uuidof(IDXGIVkPresenter),
|
if (FAILED(pDevice->QueryInterface(__uuidof(IDXGIVkPresenter),
|
||||||
@ -44,11 +47,11 @@ namespace dxvk {
|
|||||||
// shall be set to the current window size.
|
// shall be set to the current window size.
|
||||||
const VkExtent2D windowSize = GetWindowSize();
|
const VkExtent2D windowSize = GetWindowSize();
|
||||||
|
|
||||||
if (m_desc.BufferDesc.Width == 0) m_desc.BufferDesc.Width = windowSize.width;
|
if (m_desc.Width == 0) m_desc.Width = windowSize.width;
|
||||||
if (m_desc.BufferDesc.Height == 0) m_desc.BufferDesc.Height = windowSize.height;
|
if (m_desc.Height == 0) m_desc.Height = windowSize.height;
|
||||||
|
|
||||||
// Set initial window mode and fullscreen state
|
// Set initial window mode and fullscreen state
|
||||||
if (!pDesc->Windowed && FAILED(EnterFullscreenMode(nullptr)))
|
if (!m_descFs.Windowed && FAILED(EnterFullscreenMode(nullptr)))
|
||||||
throw DxvkError("DXGI: DxgiSwapChain: Failed to set initial fullscreen state");
|
throw DxvkError("DXGI: DxgiSwapChain: Failed to set initial fullscreen state");
|
||||||
|
|
||||||
if (FAILED(CreatePresenter()) || FAILED(CreateBackBuffer()))
|
if (FAILED(CreatePresenter()) || FAILED(CreateBackBuffer()))
|
||||||
@ -73,7 +76,8 @@ namespace dxvk {
|
|||||||
if (riid == __uuidof(IUnknown)
|
if (riid == __uuidof(IUnknown)
|
||||||
|| riid == __uuidof(IDXGIObject)
|
|| riid == __uuidof(IDXGIObject)
|
||||||
|| riid == __uuidof(IDXGIDeviceSubObject)
|
|| riid == __uuidof(IDXGIDeviceSubObject)
|
||||||
|| riid == __uuidof(IDXGISwapChain)) {
|
|| riid == __uuidof(IDXGISwapChain)
|
||||||
|
|| riid == __uuidof(IDXGISwapChain1)) {
|
||||||
*ppvObject = ref(this);
|
*ppvObject = ref(this);
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
@ -99,7 +103,7 @@ namespace dxvk {
|
|||||||
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(m_mutex);
|
std::lock_guard<std::recursive_mutex> lock(m_mutex);
|
||||||
|
|
||||||
if (!IsWindow(m_desc.OutputWindow))
|
if (!IsWindow(m_window))
|
||||||
return DXGI_ERROR_INVALID_CALL;
|
return DXGI_ERROR_INVALID_CALL;
|
||||||
|
|
||||||
if (Buffer > 0) {
|
if (Buffer > 0) {
|
||||||
@ -116,11 +120,11 @@ namespace dxvk {
|
|||||||
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(m_mutex);
|
std::lock_guard<std::recursive_mutex> lock(m_mutex);
|
||||||
|
|
||||||
if (!IsWindow(m_desc.OutputWindow))
|
if (!IsWindow(m_window))
|
||||||
return DXGI_ERROR_INVALID_CALL;
|
return DXGI_ERROR_INVALID_CALL;
|
||||||
|
|
||||||
RECT windowRect = { 0, 0, 0, 0 };
|
RECT windowRect = { 0, 0, 0, 0 };
|
||||||
::GetWindowRect(m_desc.OutputWindow, &windowRect);
|
::GetWindowRect(m_window, &windowRect);
|
||||||
|
|
||||||
HMONITOR monitor = ::MonitorFromPoint(
|
HMONITOR monitor = ::MonitorFromPoint(
|
||||||
{ (windowRect.left + windowRect.right) / 2,
|
{ (windowRect.left + windowRect.right) / 2,
|
||||||
@ -134,6 +138,29 @@ namespace dxvk {
|
|||||||
HRESULT STDMETHODCALLTYPE DxgiSwapChain::GetDesc(DXGI_SWAP_CHAIN_DESC* pDesc) {
|
HRESULT STDMETHODCALLTYPE DxgiSwapChain::GetDesc(DXGI_SWAP_CHAIN_DESC* pDesc) {
|
||||||
std::lock_guard<std::recursive_mutex> lock(m_mutex);
|
std::lock_guard<std::recursive_mutex> lock(m_mutex);
|
||||||
|
|
||||||
|
if (pDesc == nullptr)
|
||||||
|
return DXGI_ERROR_INVALID_CALL;
|
||||||
|
|
||||||
|
pDesc->BufferDesc.Width = m_desc.Width;
|
||||||
|
pDesc->BufferDesc.Height = m_desc.Height;
|
||||||
|
pDesc->BufferDesc.RefreshRate = m_descFs.RefreshRate;
|
||||||
|
pDesc->BufferDesc.Format = m_desc.Format;
|
||||||
|
pDesc->BufferDesc.ScanlineOrdering = m_descFs.ScanlineOrdering;
|
||||||
|
pDesc->BufferDesc.Scaling = m_descFs.Scaling;
|
||||||
|
pDesc->SampleDesc = m_desc.SampleDesc;
|
||||||
|
pDesc->BufferUsage = m_desc.BufferUsage;
|
||||||
|
pDesc->BufferCount = m_desc.BufferCount;
|
||||||
|
pDesc->OutputWindow = m_window;
|
||||||
|
pDesc->Windowed = m_descFs.Windowed;
|
||||||
|
pDesc->SwapEffect = m_desc.SwapEffect;
|
||||||
|
pDesc->Flags = m_desc.Flags;
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
HRESULT STDMETHODCALLTYPE DxgiSwapChain::GetDesc1(DXGI_SWAP_CHAIN_DESC1* pDesc) {
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(m_mutex);
|
||||||
|
|
||||||
if (pDesc == nullptr)
|
if (pDesc == nullptr)
|
||||||
return DXGI_ERROR_INVALID_CALL;
|
return DXGI_ERROR_INVALID_CALL;
|
||||||
|
|
||||||
@ -142,6 +169,29 @@ namespace dxvk {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
HRESULT STDMETHODCALLTYPE DxgiSwapChain::GetBackgroundColor(
|
||||||
|
DXGI_RGBA* pColor) {
|
||||||
|
Logger::err("DxgiSwapChain::GetBackgroundColor: Not implemented");
|
||||||
|
return E_NOTIMPL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
HRESULT STDMETHODCALLTYPE DxgiSwapChain::GetRotation(
|
||||||
|
DXGI_MODE_ROTATION* pRotation) {
|
||||||
|
Logger::err("DxgiSwapChain::GetRotation: Not implemented");
|
||||||
|
return E_NOTIMPL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
HRESULT STDMETHODCALLTYPE DxgiSwapChain::GetRestrictToOutput(
|
||||||
|
IDXGIOutput** ppRestrictToOutput) {
|
||||||
|
InitReturnPtr(ppRestrictToOutput);
|
||||||
|
|
||||||
|
Logger::err("DxgiSwapChain::GetRestrictToOutput: Not implemented");
|
||||||
|
return E_NOTIMPL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
HRESULT STDMETHODCALLTYPE DxgiSwapChain::GetFrameStatistics(DXGI_FRAME_STATISTICS* pStats) {
|
HRESULT STDMETHODCALLTYPE DxgiSwapChain::GetFrameStatistics(DXGI_FRAME_STATISTICS* pStats) {
|
||||||
std::lock_guard<std::recursive_mutex> lock(m_mutex);
|
std::lock_guard<std::recursive_mutex> lock(m_mutex);
|
||||||
|
|
||||||
@ -158,18 +208,18 @@ namespace dxvk {
|
|||||||
IDXGIOutput** ppTarget) {
|
IDXGIOutput** ppTarget) {
|
||||||
std::lock_guard<std::recursive_mutex> lock(m_mutex);
|
std::lock_guard<std::recursive_mutex> lock(m_mutex);
|
||||||
|
|
||||||
if (!IsWindow(m_desc.OutputWindow))
|
if (!IsWindow(m_window))
|
||||||
return DXGI_ERROR_INVALID_CALL;
|
return DXGI_ERROR_INVALID_CALL;
|
||||||
|
|
||||||
HRESULT hr = S_OK;
|
HRESULT hr = S_OK;
|
||||||
|
|
||||||
if (pFullscreen != nullptr)
|
if (pFullscreen != nullptr)
|
||||||
*pFullscreen = !m_desc.Windowed;
|
*pFullscreen = !m_descFs.Windowed;
|
||||||
|
|
||||||
if (ppTarget != nullptr) {
|
if (ppTarget != nullptr) {
|
||||||
*ppTarget = nullptr;
|
*ppTarget = nullptr;
|
||||||
|
|
||||||
if (!m_desc.Windowed)
|
if (!m_descFs.Windowed)
|
||||||
hr = m_adapter->GetOutputFromMonitor(m_monitor, ppTarget);
|
hr = m_adapter->GetOutputFromMonitor(m_monitor, ppTarget);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -177,6 +227,38 @@ namespace dxvk {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
HRESULT STDMETHODCALLTYPE DxgiSwapChain::GetFullscreenDesc(
|
||||||
|
DXGI_SWAP_CHAIN_FULLSCREEN_DESC* pDesc) {
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(m_mutex);
|
||||||
|
|
||||||
|
if (pDesc == nullptr)
|
||||||
|
return DXGI_ERROR_INVALID_CALL;
|
||||||
|
|
||||||
|
*pDesc = m_descFs;
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
HRESULT STDMETHODCALLTYPE DxgiSwapChain::GetHwnd(
|
||||||
|
HWND* pHwnd) {
|
||||||
|
if (pHwnd == nullptr)
|
||||||
|
return DXGI_ERROR_INVALID_CALL;
|
||||||
|
|
||||||
|
*pHwnd = m_window;
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
HRESULT STDMETHODCALLTYPE DxgiSwapChain::GetCoreWindow(
|
||||||
|
REFIID refiid,
|
||||||
|
void** ppUnk) {
|
||||||
|
InitReturnPtr(ppUnk);
|
||||||
|
|
||||||
|
Logger::err("DxgiSwapChain::GetCoreWindow: Not implemented");
|
||||||
|
return E_NOTIMPL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
HRESULT STDMETHODCALLTYPE DxgiSwapChain::GetLastPresentCount(UINT* pLastPresentCount) {
|
HRESULT STDMETHODCALLTYPE DxgiSwapChain::GetLastPresentCount(UINT* pLastPresentCount) {
|
||||||
std::lock_guard<std::recursive_mutex> lock(m_mutex);
|
std::lock_guard<std::recursive_mutex> lock(m_mutex);
|
||||||
|
|
||||||
@ -188,10 +270,17 @@ namespace dxvk {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BOOL STDMETHODCALLTYPE DxgiSwapChain::IsTemporaryMonoSupported() {
|
||||||
|
// This seems to be related to stereo 3D display
|
||||||
|
// modes, which we don't support at the moment
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
HRESULT STDMETHODCALLTYPE DxgiSwapChain::Present(UINT SyncInterval, UINT Flags) {
|
HRESULT STDMETHODCALLTYPE DxgiSwapChain::Present(UINT SyncInterval, UINT Flags) {
|
||||||
std::lock_guard<std::recursive_mutex> lock(m_mutex);
|
std::lock_guard<std::recursive_mutex> lock(m_mutex);
|
||||||
|
|
||||||
if (!IsWindow(m_desc.OutputWindow))
|
if (!IsWindow(m_window))
|
||||||
return DXGI_ERROR_INVALID_CALL;
|
return DXGI_ERROR_INVALID_CALL;
|
||||||
|
|
||||||
if (Flags & DXGI_PRESENT_TEST)
|
if (Flags & DXGI_PRESENT_TEST)
|
||||||
@ -217,15 +306,11 @@ namespace dxvk {
|
|||||||
// up vertical synchronization properly, but also apply
|
// up vertical synchronization properly, but also apply
|
||||||
// changes that were made to the window size even if the
|
// changes that were made to the window size even if the
|
||||||
// Vulkan swap chain itself remains valid.
|
// Vulkan swap chain itself remains valid.
|
||||||
DxvkSwapchainProperties swapchainProps;
|
VkPresentModeKHR presentMode = SyncInterval == 0
|
||||||
swapchainProps.preferredSurfaceFormat
|
? VK_PRESENT_MODE_IMMEDIATE_KHR
|
||||||
= m_presenter->PickSurfaceFormat(m_desc.BufferDesc.Format);
|
: VK_PRESENT_MODE_FIFO_KHR;
|
||||||
swapchainProps.preferredPresentMode = SyncInterval == 0
|
|
||||||
? m_presenter->PickPresentMode(VK_PRESENT_MODE_IMMEDIATE_KHR)
|
m_presenter->RecreateSwapchain(m_desc.Format, presentMode, GetWindowSize());
|
||||||
: m_presenter->PickPresentMode(VK_PRESENT_MODE_FIFO_KHR);
|
|
||||||
swapchainProps.preferredBufferSize = GetWindowSize();
|
|
||||||
|
|
||||||
m_presenter->RecreateSwapchain(&swapchainProps);
|
|
||||||
m_presenter->PresentImage();
|
m_presenter->PresentImage();
|
||||||
return S_OK;
|
return S_OK;
|
||||||
} catch (const DxvkError& err) {
|
} catch (const DxvkError& err) {
|
||||||
@ -235,6 +320,17 @@ namespace dxvk {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
HRESULT STDMETHODCALLTYPE DxgiSwapChain::Present1(
|
||||||
|
UINT SyncInterval,
|
||||||
|
UINT PresentFlags,
|
||||||
|
const DXGI_PRESENT_PARAMETERS* pPresentParameters) {
|
||||||
|
if (pPresentParameters != nullptr)
|
||||||
|
Logger::warn("DXGI: Present parameters not supported");
|
||||||
|
|
||||||
|
return Present(SyncInterval, PresentFlags);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
HRESULT STDMETHODCALLTYPE DxgiSwapChain::ResizeBuffers(
|
HRESULT STDMETHODCALLTYPE DxgiSwapChain::ResizeBuffers(
|
||||||
UINT BufferCount,
|
UINT BufferCount,
|
||||||
UINT Width,
|
UINT Width,
|
||||||
@ -243,19 +339,19 @@ namespace dxvk {
|
|||||||
UINT SwapChainFlags) {
|
UINT SwapChainFlags) {
|
||||||
std::lock_guard<std::recursive_mutex> lock(m_mutex);
|
std::lock_guard<std::recursive_mutex> lock(m_mutex);
|
||||||
|
|
||||||
if (!IsWindow(m_desc.OutputWindow))
|
if (!IsWindow(m_window))
|
||||||
return DXGI_ERROR_INVALID_CALL;
|
return DXGI_ERROR_INVALID_CALL;
|
||||||
|
|
||||||
const VkExtent2D windowSize = GetWindowSize();
|
const VkExtent2D windowSize = GetWindowSize();
|
||||||
|
|
||||||
m_desc.BufferDesc.Width = Width != 0 ? Width : windowSize.width;
|
m_desc.Width = Width != 0 ? Width : windowSize.width;
|
||||||
m_desc.BufferDesc.Height = Height != 0 ? Height : windowSize.height;
|
m_desc.Height = Height != 0 ? Height : windowSize.height;
|
||||||
|
|
||||||
if (BufferCount != 0)
|
if (BufferCount != 0)
|
||||||
m_desc.BufferCount = BufferCount;
|
m_desc.BufferCount = BufferCount;
|
||||||
|
|
||||||
if (NewFormat != DXGI_FORMAT_UNKNOWN)
|
if (NewFormat != DXGI_FORMAT_UNKNOWN)
|
||||||
m_desc.BufferDesc.Format = NewFormat;
|
m_desc.Format = NewFormat;
|
||||||
|
|
||||||
return CreateBackBuffer();
|
return CreateBackBuffer();
|
||||||
}
|
}
|
||||||
@ -267,29 +363,29 @@ namespace dxvk {
|
|||||||
if (pNewTargetParameters == nullptr)
|
if (pNewTargetParameters == nullptr)
|
||||||
return DXGI_ERROR_INVALID_CALL;
|
return DXGI_ERROR_INVALID_CALL;
|
||||||
|
|
||||||
if (!IsWindow(m_desc.OutputWindow))
|
if (!IsWindow(m_window))
|
||||||
return DXGI_ERROR_INVALID_CALL;
|
return DXGI_ERROR_INVALID_CALL;
|
||||||
|
|
||||||
// Update the swap chain description
|
// Update the swap chain description
|
||||||
if (pNewTargetParameters->RefreshRate.Numerator != 0)
|
if (pNewTargetParameters->RefreshRate.Numerator != 0)
|
||||||
m_desc.BufferDesc.RefreshRate = pNewTargetParameters->RefreshRate;
|
m_descFs.RefreshRate = pNewTargetParameters->RefreshRate;
|
||||||
|
|
||||||
m_desc.BufferDesc.ScanlineOrdering = pNewTargetParameters->ScanlineOrdering;
|
m_descFs.ScanlineOrdering = pNewTargetParameters->ScanlineOrdering;
|
||||||
m_desc.BufferDesc.Scaling = pNewTargetParameters->Scaling;
|
m_descFs.Scaling = pNewTargetParameters->Scaling;
|
||||||
|
|
||||||
if (m_desc.Windowed) {
|
if (m_descFs.Windowed) {
|
||||||
// Adjust window position and size
|
// Adjust window position and size
|
||||||
RECT newRect = { 0, 0, 0, 0 };
|
RECT newRect = { 0, 0, 0, 0 };
|
||||||
RECT oldRect = { 0, 0, 0, 0 };
|
RECT oldRect = { 0, 0, 0, 0 };
|
||||||
|
|
||||||
::GetWindowRect(m_desc.OutputWindow, &oldRect);
|
::GetWindowRect(m_window, &oldRect);
|
||||||
::SetRect(&newRect, 0, 0, pNewTargetParameters->Width, pNewTargetParameters->Height);
|
::SetRect(&newRect, 0, 0, pNewTargetParameters->Width, pNewTargetParameters->Height);
|
||||||
::AdjustWindowRectEx(&newRect,
|
::AdjustWindowRectEx(&newRect,
|
||||||
::GetWindowLongW(m_desc.OutputWindow, GWL_STYLE), FALSE,
|
::GetWindowLongW(m_window, GWL_STYLE), FALSE,
|
||||||
::GetWindowLongW(m_desc.OutputWindow, GWL_EXSTYLE));
|
::GetWindowLongW(m_window, GWL_EXSTYLE));
|
||||||
::SetRect(&newRect, 0, 0, newRect.right - newRect.left, newRect.bottom - newRect.top);
|
::SetRect(&newRect, 0, 0, newRect.right - newRect.left, newRect.bottom - newRect.top);
|
||||||
::OffsetRect(&newRect, oldRect.left, oldRect.top);
|
::OffsetRect(&newRect, oldRect.left, oldRect.top);
|
||||||
::MoveWindow(m_desc.OutputWindow, newRect.left, newRect.top,
|
::MoveWindow(m_window, newRect.left, newRect.top,
|
||||||
newRect.right - newRect.left, newRect.bottom - newRect.top, TRUE);
|
newRect.right - newRect.left, newRect.bottom - newRect.top, TRUE);
|
||||||
} else {
|
} else {
|
||||||
Com<IDXGIOutput> output;
|
Com<IDXGIOutput> output;
|
||||||
@ -309,7 +405,7 @@ namespace dxvk {
|
|||||||
|
|
||||||
const RECT newRect = desc.DesktopCoordinates;
|
const RECT newRect = desc.DesktopCoordinates;
|
||||||
|
|
||||||
::MoveWindow(m_desc.OutputWindow, newRect.left, newRect.top,
|
::MoveWindow(m_window, newRect.left, newRect.top,
|
||||||
newRect.right - newRect.left, newRect.bottom - newRect.top, TRUE);
|
newRect.right - newRect.left, newRect.bottom - newRect.top, TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -323,18 +419,32 @@ namespace dxvk {
|
|||||||
IDXGIOutput* pTarget) {
|
IDXGIOutput* pTarget) {
|
||||||
std::lock_guard<std::recursive_mutex> lock(m_mutex);
|
std::lock_guard<std::recursive_mutex> lock(m_mutex);
|
||||||
|
|
||||||
if (!IsWindow(m_desc.OutputWindow))
|
if (!IsWindow(m_window))
|
||||||
return DXGI_ERROR_INVALID_CALL;
|
return DXGI_ERROR_INVALID_CALL;
|
||||||
|
|
||||||
if (m_desc.Windowed && Fullscreen)
|
if (m_descFs.Windowed && Fullscreen)
|
||||||
return this->EnterFullscreenMode(pTarget);
|
return this->EnterFullscreenMode(pTarget);
|
||||||
else if (!m_desc.Windowed && !Fullscreen)
|
else if (!m_descFs.Windowed && !Fullscreen)
|
||||||
return this->LeaveFullscreenMode();
|
return this->LeaveFullscreenMode();
|
||||||
|
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
HRESULT STDMETHODCALLTYPE DxgiSwapChain::SetBackgroundColor(
|
||||||
|
const DXGI_RGBA* pColor) {
|
||||||
|
Logger::err("DxgiSwapChain::SetBackgroundColor: Not implemented");
|
||||||
|
return E_NOTIMPL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
HRESULT STDMETHODCALLTYPE DxgiSwapChain::SetRotation(
|
||||||
|
DXGI_MODE_ROTATION Rotation) {
|
||||||
|
Logger::err("DxgiSwapChain::SetRotation: Not implemented");
|
||||||
|
return E_NOTIMPL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
HRESULT DxgiSwapChain::SetGammaControl(const DXGI_GAMMA_CONTROL* pGammaControl) {
|
HRESULT DxgiSwapChain::SetGammaControl(const DXGI_GAMMA_CONTROL* pGammaControl) {
|
||||||
std::lock_guard<std::recursive_mutex> lock(m_mutex);
|
std::lock_guard<std::recursive_mutex> lock(m_mutex);
|
||||||
|
|
||||||
@ -373,7 +483,7 @@ namespace dxvk {
|
|||||||
try {
|
try {
|
||||||
m_presenter = new DxgiVkPresenter(
|
m_presenter = new DxgiVkPresenter(
|
||||||
m_device->GetDXVKDevice(),
|
m_device->GetDXVKDevice(),
|
||||||
m_desc.OutputWindow);
|
m_window);
|
||||||
return S_OK;
|
return S_OK;
|
||||||
} catch (const DxvkError& e) {
|
} catch (const DxvkError& e) {
|
||||||
Logger::err(e.message());
|
Logger::err(e.message());
|
||||||
@ -412,7 +522,7 @@ namespace dxvk {
|
|||||||
VkExtent2D DxgiSwapChain::GetWindowSize() const {
|
VkExtent2D DxgiSwapChain::GetWindowSize() const {
|
||||||
RECT windowRect;
|
RECT windowRect;
|
||||||
|
|
||||||
if (!::GetClientRect(m_desc.OutputWindow, &windowRect))
|
if (!::GetClientRect(m_window, &windowRect))
|
||||||
windowRect = RECT();
|
windowRect = RECT();
|
||||||
|
|
||||||
VkExtent2D result;
|
VkExtent2D result;
|
||||||
@ -433,14 +543,18 @@ namespace dxvk {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Find a display mode that matches what we need
|
// Find a display mode that matches what we need
|
||||||
::GetWindowRect(m_desc.OutputWindow, &m_windowState.rect);
|
::GetWindowRect(m_window, &m_windowState.rect);
|
||||||
|
|
||||||
if (m_desc.Flags & DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH) {
|
if (m_desc.Flags & DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH) {
|
||||||
auto windowRect = m_windowState.rect;
|
auto windowRect = m_windowState.rect;
|
||||||
|
|
||||||
DXGI_MODE_DESC displayMode = m_desc.BufferDesc;
|
DXGI_MODE_DESC displayMode;
|
||||||
displayMode.Width = windowRect.right - windowRect.left;
|
displayMode.Width = windowRect.right - windowRect.left;
|
||||||
displayMode.Height = windowRect.bottom - windowRect.top;
|
displayMode.Height = windowRect.bottom - windowRect.top;
|
||||||
|
displayMode.RefreshRate = m_descFs.RefreshRate;
|
||||||
|
displayMode.Format = m_desc.Format;
|
||||||
|
displayMode.ScanlineOrdering = m_descFs.ScanlineOrdering;
|
||||||
|
displayMode.Scaling = m_descFs.Scaling;
|
||||||
|
|
||||||
if (FAILED(ChangeDisplayMode(output.ptr(), &displayMode))) {
|
if (FAILED(ChangeDisplayMode(output.ptr(), &displayMode))) {
|
||||||
Logger::err("DXGI: EnterFullscreenMode: Failed to change display mode");
|
Logger::err("DXGI: EnterFullscreenMode: Failed to change display mode");
|
||||||
@ -449,11 +563,11 @@ namespace dxvk {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Update swap chain description
|
// Update swap chain description
|
||||||
m_desc.Windowed = FALSE;
|
m_descFs.Windowed = FALSE;
|
||||||
|
|
||||||
// Change the window flags to remove the decoration etc.
|
// Change the window flags to remove the decoration etc.
|
||||||
LONG style = ::GetWindowLongW(m_desc.OutputWindow, GWL_STYLE);
|
LONG style = ::GetWindowLongW(m_window, GWL_STYLE);
|
||||||
LONG exstyle = ::GetWindowLongW(m_desc.OutputWindow, GWL_EXSTYLE);
|
LONG exstyle = ::GetWindowLongW(m_window, GWL_EXSTYLE);
|
||||||
|
|
||||||
m_windowState.style = style;
|
m_windowState.style = style;
|
||||||
m_windowState.exstyle = exstyle;
|
m_windowState.exstyle = exstyle;
|
||||||
@ -461,8 +575,8 @@ namespace dxvk {
|
|||||||
style &= ~WS_OVERLAPPEDWINDOW;
|
style &= ~WS_OVERLAPPEDWINDOW;
|
||||||
exstyle &= ~WS_EX_OVERLAPPEDWINDOW;
|
exstyle &= ~WS_EX_OVERLAPPEDWINDOW;
|
||||||
|
|
||||||
::SetWindowLongW(m_desc.OutputWindow, GWL_STYLE, style);
|
::SetWindowLongW(m_window, GWL_STYLE, style);
|
||||||
::SetWindowLongW(m_desc.OutputWindow, GWL_EXSTYLE, exstyle);
|
::SetWindowLongW(m_window, GWL_EXSTYLE, exstyle);
|
||||||
|
|
||||||
// Move the window so that it covers the entire output
|
// Move the window so that it covers the entire output
|
||||||
DXGI_OUTPUT_DESC desc;
|
DXGI_OUTPUT_DESC desc;
|
||||||
@ -470,7 +584,7 @@ namespace dxvk {
|
|||||||
|
|
||||||
const RECT rect = desc.DesktopCoordinates;
|
const RECT rect = desc.DesktopCoordinates;
|
||||||
|
|
||||||
::SetWindowPos(m_desc.OutputWindow, HWND_TOPMOST,
|
::SetWindowPos(m_window, HWND_TOPMOST,
|
||||||
rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
|
rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
|
||||||
SWP_FRAMECHANGED | SWP_SHOWWINDOW | SWP_NOACTIVATE);
|
SWP_FRAMECHANGED | SWP_SHOWWINDOW | SWP_NOACTIVATE);
|
||||||
|
|
||||||
@ -487,24 +601,24 @@ namespace dxvk {
|
|||||||
Logger::warn("DXGI: LeaveFullscreenMode: Failed to restore display mode");
|
Logger::warn("DXGI: LeaveFullscreenMode: Failed to restore display mode");
|
||||||
|
|
||||||
// Restore internal state
|
// Restore internal state
|
||||||
m_desc.Windowed = TRUE;
|
m_descFs.Windowed = TRUE;
|
||||||
m_monitor = nullptr;
|
m_monitor = nullptr;
|
||||||
|
|
||||||
// Only restore the window style if the application hasn't
|
// Only restore the window style if the application hasn't
|
||||||
// changed them. This is in line with what native DXGI does.
|
// changed them. This is in line with what native DXGI does.
|
||||||
LONG curStyle = ::GetWindowLongW(m_desc.OutputWindow, GWL_STYLE) & ~WS_VISIBLE;
|
LONG curStyle = ::GetWindowLongW(m_window, GWL_STYLE) & ~WS_VISIBLE;
|
||||||
LONG curExstyle = ::GetWindowLongW(m_desc.OutputWindow, GWL_EXSTYLE) & ~WS_EX_TOPMOST;
|
LONG curExstyle = ::GetWindowLongW(m_window, GWL_EXSTYLE) & ~WS_EX_TOPMOST;
|
||||||
|
|
||||||
if (curStyle == (m_windowState.style & ~(WS_VISIBLE | WS_OVERLAPPEDWINDOW))
|
if (curStyle == (m_windowState.style & ~(WS_VISIBLE | WS_OVERLAPPEDWINDOW))
|
||||||
&& curExstyle == (m_windowState.exstyle & ~(WS_EX_TOPMOST | WS_EX_OVERLAPPEDWINDOW))) {
|
&& curExstyle == (m_windowState.exstyle & ~(WS_EX_TOPMOST | WS_EX_OVERLAPPEDWINDOW))) {
|
||||||
::SetWindowLongW(m_desc.OutputWindow, GWL_STYLE, m_windowState.style);
|
::SetWindowLongW(m_window, GWL_STYLE, m_windowState.style);
|
||||||
::SetWindowLongW(m_desc.OutputWindow, GWL_EXSTYLE, m_windowState.exstyle);
|
::SetWindowLongW(m_window, GWL_EXSTYLE, m_windowState.exstyle);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Restore window position and apply the style
|
// Restore window position and apply the style
|
||||||
const RECT rect = m_windowState.rect;
|
const RECT rect = m_windowState.rect;
|
||||||
|
|
||||||
::SetWindowPos(m_desc.OutputWindow, 0,
|
::SetWindowPos(m_window, 0,
|
||||||
rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
|
rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
|
||||||
SWP_FRAMECHANGED | SWP_NOZORDER | SWP_NOACTIVATE);
|
SWP_FRAMECHANGED | SWP_NOZORDER | SWP_NOACTIVATE);
|
||||||
|
|
||||||
|
@ -20,69 +20,107 @@ namespace dxvk {
|
|||||||
class DxgiFactory;
|
class DxgiFactory;
|
||||||
class DxgiOutput;
|
class DxgiOutput;
|
||||||
|
|
||||||
class DxgiSwapChain : public DxgiObject<IDXGISwapChain> {
|
class DxgiSwapChain : public DxgiObject<IDXGISwapChain1> {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
DxgiSwapChain(
|
DxgiSwapChain(
|
||||||
DxgiFactory* factory,
|
DxgiFactory* pFactory,
|
||||||
IUnknown* pDevice,
|
IUnknown* pDevice,
|
||||||
DXGI_SWAP_CHAIN_DESC* pDesc);
|
HWND hWnd,
|
||||||
|
const DXGI_SWAP_CHAIN_DESC1* pDesc,
|
||||||
|
const DXGI_SWAP_CHAIN_FULLSCREEN_DESC* pFullscreenDesc);
|
||||||
|
|
||||||
~DxgiSwapChain();
|
~DxgiSwapChain();
|
||||||
|
|
||||||
HRESULT STDMETHODCALLTYPE QueryInterface(
|
HRESULT STDMETHODCALLTYPE QueryInterface(
|
||||||
REFIID riid,
|
REFIID riid,
|
||||||
void** ppvObject) final;
|
void** ppvObject) final;
|
||||||
|
|
||||||
HRESULT STDMETHODCALLTYPE GetParent(
|
HRESULT STDMETHODCALLTYPE GetParent(
|
||||||
REFIID riid,
|
REFIID riid,
|
||||||
void** ppParent) final;
|
void** ppParent) final;
|
||||||
|
|
||||||
HRESULT STDMETHODCALLTYPE GetDevice(
|
HRESULT STDMETHODCALLTYPE GetDevice(
|
||||||
REFIID riid,
|
REFIID riid,
|
||||||
void** ppDevice) final;
|
void** ppDevice) final;
|
||||||
|
|
||||||
HRESULT STDMETHODCALLTYPE GetBuffer(
|
HRESULT STDMETHODCALLTYPE GetBuffer(
|
||||||
UINT Buffer,
|
UINT Buffer,
|
||||||
REFIID riid,
|
REFIID riid,
|
||||||
void** ppSurface) final;
|
void** ppSurface) final;
|
||||||
|
|
||||||
HRESULT STDMETHODCALLTYPE GetContainingOutput(
|
HRESULT STDMETHODCALLTYPE GetContainingOutput(
|
||||||
IDXGIOutput** ppOutput) final;
|
IDXGIOutput** ppOutput) final;
|
||||||
|
|
||||||
HRESULT STDMETHODCALLTYPE GetDesc(
|
HRESULT STDMETHODCALLTYPE GetDesc(
|
||||||
DXGI_SWAP_CHAIN_DESC* pDesc) final;
|
DXGI_SWAP_CHAIN_DESC* pDesc) final;
|
||||||
|
|
||||||
HRESULT STDMETHODCALLTYPE GetFrameStatistics(
|
HRESULT STDMETHODCALLTYPE GetDesc1(
|
||||||
DXGI_FRAME_STATISTICS* pStats) final;
|
DXGI_SWAP_CHAIN_DESC1* pDesc) final;
|
||||||
|
|
||||||
HRESULT STDMETHODCALLTYPE GetFullscreenState(
|
HRESULT STDMETHODCALLTYPE GetFullscreenState(
|
||||||
BOOL* pFullscreen,
|
BOOL* pFullscreen,
|
||||||
IDXGIOutput** ppTarget) final;
|
IDXGIOutput** ppTarget) final;
|
||||||
|
|
||||||
|
HRESULT STDMETHODCALLTYPE GetFullscreenDesc(
|
||||||
|
DXGI_SWAP_CHAIN_FULLSCREEN_DESC* pDesc) final;
|
||||||
|
|
||||||
|
HRESULT STDMETHODCALLTYPE GetHwnd(
|
||||||
|
HWND* pHwnd) final;
|
||||||
|
|
||||||
|
HRESULT STDMETHODCALLTYPE GetCoreWindow(
|
||||||
|
REFIID refiid,
|
||||||
|
void** ppUnk) final;
|
||||||
|
|
||||||
|
HRESULT STDMETHODCALLTYPE GetBackgroundColor(
|
||||||
|
DXGI_RGBA* pColor) final;
|
||||||
|
|
||||||
|
HRESULT STDMETHODCALLTYPE GetRotation(
|
||||||
|
DXGI_MODE_ROTATION* pRotation) final;
|
||||||
|
|
||||||
|
HRESULT STDMETHODCALLTYPE GetRestrictToOutput(
|
||||||
|
IDXGIOutput** ppRestrictToOutput) final;
|
||||||
|
|
||||||
|
HRESULT STDMETHODCALLTYPE GetFrameStatistics(
|
||||||
|
DXGI_FRAME_STATISTICS* pStats) final;
|
||||||
|
|
||||||
HRESULT STDMETHODCALLTYPE GetLastPresentCount(
|
HRESULT STDMETHODCALLTYPE GetLastPresentCount(
|
||||||
UINT* pLastPresentCount) final;
|
UINT* pLastPresentCount) final;
|
||||||
|
|
||||||
|
BOOL STDMETHODCALLTYPE IsTemporaryMonoSupported() final;
|
||||||
|
|
||||||
HRESULT STDMETHODCALLTYPE Present(
|
HRESULT STDMETHODCALLTYPE Present(
|
||||||
UINT SyncInterval,
|
UINT SyncInterval,
|
||||||
UINT Flags) final;
|
UINT Flags) final;
|
||||||
|
|
||||||
|
HRESULT STDMETHODCALLTYPE Present1(
|
||||||
|
UINT SyncInterval,
|
||||||
|
UINT PresentFlags,
|
||||||
|
const DXGI_PRESENT_PARAMETERS* pPresentParameters) final;
|
||||||
|
|
||||||
HRESULT STDMETHODCALLTYPE ResizeBuffers(
|
HRESULT STDMETHODCALLTYPE ResizeBuffers(
|
||||||
UINT BufferCount,
|
UINT BufferCount,
|
||||||
UINT Width,
|
UINT Width,
|
||||||
UINT Height,
|
UINT Height,
|
||||||
DXGI_FORMAT NewFormat,
|
DXGI_FORMAT NewFormat,
|
||||||
UINT SwapChainFlags) final;
|
UINT SwapChainFlags) final;
|
||||||
|
|
||||||
HRESULT STDMETHODCALLTYPE ResizeTarget(
|
HRESULT STDMETHODCALLTYPE ResizeTarget(
|
||||||
const DXGI_MODE_DESC* pNewTargetParameters) final;
|
const DXGI_MODE_DESC* pNewTargetParameters) final;
|
||||||
|
|
||||||
HRESULT STDMETHODCALLTYPE SetFullscreenState(
|
HRESULT STDMETHODCALLTYPE SetFullscreenState(
|
||||||
BOOL Fullscreen,
|
BOOL Fullscreen,
|
||||||
IDXGIOutput* pTarget) final;
|
IDXGIOutput* pTarget) final;
|
||||||
|
|
||||||
|
HRESULT STDMETHODCALLTYPE SetBackgroundColor(
|
||||||
|
const DXGI_RGBA* pColor) final;
|
||||||
|
|
||||||
|
HRESULT STDMETHODCALLTYPE SetRotation(
|
||||||
|
DXGI_MODE_ROTATION Rotation) final;
|
||||||
|
|
||||||
HRESULT SetGammaControl(
|
HRESULT SetGammaControl(
|
||||||
const DXGI_GAMMA_CONTROL* pGammaControl);
|
const DXGI_GAMMA_CONTROL* pGammaControl);
|
||||||
|
|
||||||
HRESULT SetDefaultGammaControl();
|
HRESULT SetDefaultGammaControl();
|
||||||
|
|
||||||
@ -101,7 +139,9 @@ namespace dxvk {
|
|||||||
Com<DxgiDevice> m_device;
|
Com<DxgiDevice> m_device;
|
||||||
Com<IDXGIVkPresenter> m_presentDevice;
|
Com<IDXGIVkPresenter> m_presentDevice;
|
||||||
|
|
||||||
DXGI_SWAP_CHAIN_DESC m_desc;
|
HWND m_window;
|
||||||
|
DXGI_SWAP_CHAIN_DESC1 m_desc;
|
||||||
|
DXGI_SWAP_CHAIN_FULLSCREEN_DESC m_descFs;
|
||||||
DXGI_FRAME_STATISTICS m_stats;
|
DXGI_FRAME_STATISTICS m_stats;
|
||||||
|
|
||||||
Rc<DxgiVkPresenter> m_presenter;
|
Rc<DxgiVkPresenter> m_presenter;
|
||||||
|
@ -10,6 +10,7 @@ dxgi_src = [
|
|||||||
'dxgi_factory.cpp',
|
'dxgi_factory.cpp',
|
||||||
'dxgi_format.cpp',
|
'dxgi_format.cpp',
|
||||||
'dxgi_main.cpp',
|
'dxgi_main.cpp',
|
||||||
|
'dxgi_options.cpp',
|
||||||
'dxgi_output.cpp',
|
'dxgi_output.cpp',
|
||||||
'dxgi_presenter.cpp',
|
'dxgi_presenter.cpp',
|
||||||
'dxgi_swapchain.cpp',
|
'dxgi_swapchain.cpp',
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include "dxvk_compute.h"
|
#include "dxvk_compute.h"
|
||||||
#include "dxvk_device.h"
|
#include "dxvk_device.h"
|
||||||
|
#include "dxvk_spec_const.h"
|
||||||
|
|
||||||
namespace dxvk {
|
namespace dxvk {
|
||||||
|
|
||||||
@ -99,19 +100,16 @@ namespace dxvk {
|
|||||||
Logger::debug(str::format(" cs : ", m_cs->shader()->debugName()));
|
Logger::debug(str::format(" cs : ", m_cs->shader()->debugName()));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::array<VkBool32, MaxNumActiveBindings> specData;
|
DxvkSpecConstantData specData;
|
||||||
std::array<VkSpecializationMapEntry, MaxNumActiveBindings> specMap;
|
|
||||||
|
|
||||||
for (uint32_t i = 0; i < MaxNumActiveBindings; i++) {
|
for (uint32_t i = 0; i < MaxNumActiveBindings; i++)
|
||||||
specData[i] = state.bsBindingState.isBound(i) ? VK_TRUE : VK_FALSE;
|
specData.activeBindings[i] = state.bsBindingState.isBound(i) ? VK_TRUE : VK_FALSE;
|
||||||
specMap [i] = { i, static_cast<uint32_t>(sizeof(VkBool32)) * i, sizeof(VkBool32) };
|
|
||||||
}
|
|
||||||
|
|
||||||
VkSpecializationInfo specInfo;
|
VkSpecializationInfo specInfo;
|
||||||
specInfo.mapEntryCount = specMap.size();
|
specInfo.mapEntryCount = g_specConstantMap.mapEntryCount();
|
||||||
specInfo.pMapEntries = specMap.data();
|
specInfo.pMapEntries = g_specConstantMap.mapEntryData();
|
||||||
specInfo.dataSize = specData.size() * sizeof(VkBool32);
|
specInfo.dataSize = sizeof(specData);
|
||||||
specInfo.pData = specData.data();
|
specInfo.pData = &specData;
|
||||||
|
|
||||||
VkComputePipelineCreateInfo info;
|
VkComputePipelineCreateInfo info;
|
||||||
info.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO;
|
info.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO;
|
||||||
|
@ -7,12 +7,14 @@
|
|||||||
namespace dxvk {
|
namespace dxvk {
|
||||||
|
|
||||||
DxvkContext::DxvkContext(
|
DxvkContext::DxvkContext(
|
||||||
const Rc<DxvkDevice>& device,
|
const Rc<DxvkDevice>& device,
|
||||||
const Rc<DxvkPipelineManager>& pipelineManager,
|
const Rc<DxvkPipelineManager>& pipelineManager,
|
||||||
const Rc<DxvkMetaClearObjects>& metaClearObjects)
|
const Rc<DxvkMetaClearObjects>& metaClearObjects,
|
||||||
|
const Rc<DxvkMetaMipGenObjects>& metaMipGenObjects)
|
||||||
: m_device (device),
|
: m_device (device),
|
||||||
m_pipeMgr (pipelineManager),
|
m_pipeMgr (pipelineManager),
|
||||||
m_metaClear (metaClearObjects) { }
|
m_metaClear (metaClearObjects),
|
||||||
|
m_metaMipGen(metaMipGenObjects) { }
|
||||||
|
|
||||||
|
|
||||||
DxvkContext::~DxvkContext() {
|
DxvkContext::~DxvkContext() {
|
||||||
@ -228,6 +230,9 @@ namespace dxvk {
|
|||||||
uint32_t value) {
|
uint32_t value) {
|
||||||
this->spillRenderPass();
|
this->spillRenderPass();
|
||||||
|
|
||||||
|
if (length == buffer->info().size)
|
||||||
|
length = align(length, 4);
|
||||||
|
|
||||||
auto slice = buffer->subSlice(offset, length);
|
auto slice = buffer->subSlice(offset, length);
|
||||||
|
|
||||||
m_cmd->cmdFillBuffer(
|
m_cmd->cmdFillBuffer(
|
||||||
@ -976,123 +981,102 @@ namespace dxvk {
|
|||||||
|
|
||||||
|
|
||||||
void DxvkContext::generateMipmaps(
|
void DxvkContext::generateMipmaps(
|
||||||
const Rc<DxvkImage>& image,
|
const Rc<DxvkImageView>& imageView) {
|
||||||
const VkImageSubresourceRange& subresources) {
|
if (imageView->info().numLevels <= 1)
|
||||||
if (subresources.levelCount <= 1)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
this->spillRenderPass();
|
this->spillRenderPass();
|
||||||
|
this->unbindGraphicsPipeline();
|
||||||
// The top-most level will only be read. We can
|
|
||||||
// discard the contents of all the lower levels
|
|
||||||
// since we're going to override them anyway.
|
|
||||||
m_barriers.accessImage(image,
|
|
||||||
VkImageSubresourceRange {
|
|
||||||
subresources.aspectMask,
|
|
||||||
subresources.baseMipLevel, 1,
|
|
||||||
subresources.baseArrayLayer,
|
|
||||||
subresources.layerCount },
|
|
||||||
image->info().layout,
|
|
||||||
image->info().stages,
|
|
||||||
image->info().access,
|
|
||||||
image->pickLayout(VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL),
|
|
||||||
VK_PIPELINE_STAGE_TRANSFER_BIT,
|
|
||||||
VK_ACCESS_TRANSFER_READ_BIT);
|
|
||||||
|
|
||||||
m_barriers.accessImage(image,
|
// Create the a set of framebuffers and image views
|
||||||
VkImageSubresourceRange {
|
const Rc<DxvkMetaMipGenRenderPass> mipGenerator
|
||||||
subresources.aspectMask,
|
= new DxvkMetaMipGenRenderPass(m_device->vkd(), imageView);
|
||||||
subresources.baseMipLevel + 1,
|
|
||||||
subresources.levelCount - 1,
|
|
||||||
subresources.baseArrayLayer,
|
|
||||||
subresources.layerCount },
|
|
||||||
VK_IMAGE_LAYOUT_UNDEFINED,
|
|
||||||
image->info().stages,
|
|
||||||
image->info().access,
|
|
||||||
image->pickLayout(VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL),
|
|
||||||
VK_PIPELINE_STAGE_TRANSFER_BIT,
|
|
||||||
VK_ACCESS_TRANSFER_WRITE_BIT);
|
|
||||||
|
|
||||||
m_barriers.recordCommands(m_cmd);
|
// Common descriptor set properties that we use to
|
||||||
|
// bind the source image view to the fragment shader
|
||||||
|
VkDescriptorImageInfo descriptorImage;
|
||||||
|
descriptorImage.sampler = VK_NULL_HANDLE;
|
||||||
|
descriptorImage.imageView = VK_NULL_HANDLE;
|
||||||
|
descriptorImage.imageLayout = imageView->imageInfo().layout;
|
||||||
|
|
||||||
// Generate each individual mip level with a blit
|
VkWriteDescriptorSet descriptorWrite;
|
||||||
for (uint32_t i = 1; i < subresources.levelCount; i++) {
|
descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||||
const uint32_t mip = subresources.baseMipLevel + i;
|
descriptorWrite.pNext = nullptr;
|
||||||
|
descriptorWrite.dstSet = VK_NULL_HANDLE;
|
||||||
|
descriptorWrite.dstBinding = 0;
|
||||||
|
descriptorWrite.dstArrayElement = 0;
|
||||||
|
descriptorWrite.descriptorCount = 1;
|
||||||
|
descriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||||
|
descriptorWrite.pImageInfo = &descriptorImage;
|
||||||
|
descriptorWrite.pBufferInfo = nullptr;
|
||||||
|
descriptorWrite.pTexelBufferView = nullptr;
|
||||||
|
|
||||||
|
// Common render pass info
|
||||||
|
VkRenderPassBeginInfo passInfo;
|
||||||
|
passInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
|
||||||
|
passInfo.pNext = nullptr;
|
||||||
|
passInfo.renderPass = mipGenerator->renderPass();
|
||||||
|
passInfo.framebuffer = VK_NULL_HANDLE;
|
||||||
|
passInfo.renderArea = VkRect2D { };
|
||||||
|
passInfo.clearValueCount = 0;
|
||||||
|
passInfo.pClearValues = nullptr;
|
||||||
|
|
||||||
|
// Retrieve a compatible pipeline to use for rendering
|
||||||
|
DxvkMetaMipGenPipeline pipeInfo = m_metaMipGen->getPipeline(
|
||||||
|
mipGenerator->viewType(), imageView->info().format);
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < mipGenerator->passCount(); i++) {
|
||||||
|
DxvkMetaMipGenPass pass = mipGenerator->pass(i);
|
||||||
|
|
||||||
const VkExtent3D srcExtent = image->mipLevelExtent(mip - 1);
|
// Width, height and layer count for the current pass
|
||||||
const VkExtent3D dstExtent = image->mipLevelExtent(mip);
|
VkExtent3D passExtent = mipGenerator->passExtent(i);
|
||||||
|
|
||||||
VkImageBlit region;
|
// Create descriptor set with the current source view
|
||||||
region.srcSubresource = VkImageSubresourceLayers {
|
descriptorImage.imageView = pass.srcView;
|
||||||
subresources.aspectMask, mip - 1,
|
descriptorWrite.dstSet = m_cmd->allocateDescriptorSet(pipeInfo.dsetLayout);
|
||||||
subresources.baseArrayLayer,
|
m_cmd->updateDescriptorSets(1, &descriptorWrite);
|
||||||
subresources.layerCount };
|
|
||||||
region.srcOffsets[0] = VkOffset3D { 0, 0, 0 };
|
|
||||||
region.srcOffsets[1].x = srcExtent.width;
|
|
||||||
region.srcOffsets[1].y = srcExtent.height;
|
|
||||||
region.srcOffsets[1].z = srcExtent.depth;
|
|
||||||
|
|
||||||
region.dstSubresource = VkImageSubresourceLayers {
|
// Set up viewport and scissor rect
|
||||||
subresources.aspectMask, mip,
|
VkViewport viewport;
|
||||||
subresources.baseArrayLayer,
|
viewport.x = 0.0f;
|
||||||
subresources.layerCount };
|
viewport.y = 0.0f;
|
||||||
region.dstOffsets[0] = VkOffset3D { 0, 0, 0 };
|
viewport.width = float(passExtent.width);
|
||||||
region.dstOffsets[1].x = dstExtent.width;
|
viewport.height = float(passExtent.height);
|
||||||
region.dstOffsets[1].y = dstExtent.height;
|
viewport.minDepth = 0.0f;
|
||||||
region.dstOffsets[1].z = dstExtent.depth;
|
viewport.maxDepth = 1.0f;
|
||||||
|
|
||||||
m_cmd->cmdBlitImage(
|
VkRect2D scissor;
|
||||||
image->handle(), image->pickLayout(VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL),
|
scissor.offset = { 0, 0 };
|
||||||
image->handle(), image->pickLayout(VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL),
|
scissor.extent = { passExtent.width, passExtent.height };
|
||||||
1, ®ion, VK_FILTER_LINEAR);
|
|
||||||
|
|
||||||
if (i + 1 < subresources.levelCount) {
|
// Set up render pass info
|
||||||
m_barriers.accessImage(image,
|
passInfo.framebuffer = pass.framebuffer;
|
||||||
VkImageSubresourceRange {
|
passInfo.renderArea = scissor;
|
||||||
subresources.aspectMask, mip, 1,
|
|
||||||
subresources.baseArrayLayer,
|
// Set up push constants
|
||||||
subresources.layerCount },
|
DxvkMetaMipGenPushConstants pushConstants;
|
||||||
image->pickLayout(VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL),
|
pushConstants.layerCount = passExtent.depth;
|
||||||
VK_PIPELINE_STAGE_TRANSFER_BIT,
|
|
||||||
VK_ACCESS_TRANSFER_WRITE_BIT,
|
m_cmd->cmdBeginRenderPass(&passInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||||
image->pickLayout(VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL),
|
m_cmd->cmdBindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeInfo.pipeHandle);
|
||||||
VK_PIPELINE_STAGE_TRANSFER_BIT,
|
m_cmd->cmdBindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS,
|
||||||
VK_ACCESS_TRANSFER_READ_BIT);
|
pipeInfo.pipeLayout, descriptorWrite.dstSet);
|
||||||
m_barriers.recordCommands(m_cmd);
|
|
||||||
}
|
m_cmd->cmdSetViewport(0, 1, &viewport);
|
||||||
|
m_cmd->cmdSetScissor (0, 1, &scissor);
|
||||||
|
|
||||||
|
m_cmd->cmdPushConstants(
|
||||||
|
pipeInfo.pipeLayout,
|
||||||
|
VK_SHADER_STAGE_FRAGMENT_BIT,
|
||||||
|
0, sizeof(pushConstants),
|
||||||
|
&pushConstants);
|
||||||
|
|
||||||
|
m_cmd->cmdDraw(1, passExtent.depth, 0, 0);
|
||||||
|
m_cmd->cmdEndRenderPass();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Transform mip levels back into their original layout.
|
m_cmd->trackResource(mipGenerator);
|
||||||
// The last mip level is still in TRANSFER_DST_OPTIMAL.
|
m_cmd->trackResource(imageView->image());
|
||||||
m_barriers.accessImage(image,
|
|
||||||
VkImageSubresourceRange {
|
|
||||||
subresources.aspectMask,
|
|
||||||
subresources.baseMipLevel,
|
|
||||||
subresources.levelCount - 1,
|
|
||||||
subresources.baseArrayLayer,
|
|
||||||
subresources.layerCount },
|
|
||||||
image->pickLayout(VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL),
|
|
||||||
VK_PIPELINE_STAGE_TRANSFER_BIT,
|
|
||||||
VK_ACCESS_TRANSFER_READ_BIT,
|
|
||||||
image->info().layout,
|
|
||||||
image->info().stages,
|
|
||||||
image->info().access);
|
|
||||||
|
|
||||||
m_barriers.accessImage(image,
|
|
||||||
VkImageSubresourceRange {
|
|
||||||
subresources.aspectMask,
|
|
||||||
subresources.baseMipLevel
|
|
||||||
+ subresources.levelCount - 1, 1,
|
|
||||||
subresources.baseArrayLayer,
|
|
||||||
subresources.layerCount },
|
|
||||||
image->pickLayout(VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL),
|
|
||||||
VK_PIPELINE_STAGE_TRANSFER_BIT,
|
|
||||||
VK_ACCESS_TRANSFER_WRITE_BIT,
|
|
||||||
image->info().layout,
|
|
||||||
image->info().stages,
|
|
||||||
image->info().access);
|
|
||||||
|
|
||||||
m_barriers.recordCommands(m_cmd);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1399,15 +1383,19 @@ namespace dxvk {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m_cmd->cmdSetViewport(0, viewportCount, m_state.vp.viewports.data());
|
if (m_gpActivePipeline != VK_NULL_HANDLE) {
|
||||||
m_cmd->cmdSetScissor (0, viewportCount, m_state.vp.scissorRects.data());
|
m_cmd->cmdSetViewport(0, viewportCount, m_state.vp.viewports.data());
|
||||||
|
m_cmd->cmdSetScissor (0, viewportCount, m_state.vp.scissorRects.data());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void DxvkContext::setBlendConstants(
|
void DxvkContext::setBlendConstants(
|
||||||
const DxvkBlendConstants& blendConstants) {
|
const DxvkBlendConstants& blendConstants) {
|
||||||
m_state.om.blendConstants = blendConstants;
|
m_state.om.blendConstants = blendConstants;
|
||||||
m_cmd->cmdSetBlendConstants(&blendConstants.r);
|
|
||||||
|
if (m_gpActivePipeline != VK_NULL_HANDLE)
|
||||||
|
m_cmd->cmdSetBlendConstants(&blendConstants.r);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1415,9 +1403,11 @@ namespace dxvk {
|
|||||||
const uint32_t reference) {
|
const uint32_t reference) {
|
||||||
m_state.om.stencilReference = reference;
|
m_state.om.stencilReference = reference;
|
||||||
|
|
||||||
m_cmd->cmdSetStencilReference(
|
if (m_gpActivePipeline != VK_NULL_HANDLE) {
|
||||||
VK_STENCIL_FRONT_AND_BACK,
|
m_cmd->cmdSetStencilReference(
|
||||||
reference);
|
VK_STENCIL_FRONT_AND_BACK,
|
||||||
|
reference);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1680,6 +1670,18 @@ namespace dxvk {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void DxvkContext::unbindGraphicsPipeline() {
|
||||||
|
m_flags.set(
|
||||||
|
DxvkContextFlag::GpDirtyPipeline,
|
||||||
|
DxvkContextFlag::GpDirtyPipelineState,
|
||||||
|
DxvkContextFlag::GpDirtyResources,
|
||||||
|
DxvkContextFlag::GpDirtyVertexBuffers,
|
||||||
|
DxvkContextFlag::GpDirtyIndexBuffer);
|
||||||
|
|
||||||
|
m_gpActivePipeline = VK_NULL_HANDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void DxvkContext::updateGraphicsPipeline() {
|
void DxvkContext::updateGraphicsPipeline() {
|
||||||
if (m_flags.test(DxvkContextFlag::GpDirtyPipeline)) {
|
if (m_flags.test(DxvkContextFlag::GpDirtyPipeline)) {
|
||||||
m_flags.clr(DxvkContextFlag::GpDirtyPipeline);
|
m_flags.clr(DxvkContextFlag::GpDirtyPipeline);
|
||||||
@ -1822,11 +1824,11 @@ namespace dxvk {
|
|||||||
|
|
||||||
case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
|
case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
|
||||||
case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
|
case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
|
||||||
if (res.imageView != nullptr && res.imageView->type() == binding.view) {
|
if (res.imageView != nullptr && res.imageView->handle(binding.view) != VK_NULL_HANDLE) {
|
||||||
updatePipelineState |= bindingState.setBound(i);
|
updatePipelineState |= bindingState.setBound(i);
|
||||||
|
|
||||||
m_descInfos[i].image.sampler = VK_NULL_HANDLE;
|
m_descInfos[i].image.sampler = VK_NULL_HANDLE;
|
||||||
m_descInfos[i].image.imageView = res.imageView->handle();
|
m_descInfos[i].image.imageView = res.imageView->handle(binding.view);
|
||||||
m_descInfos[i].image.imageLayout = res.imageView->imageInfo().layout;
|
m_descInfos[i].image.imageLayout = res.imageView->imageInfo().layout;
|
||||||
|
|
||||||
if (depthAttachment.view != nullptr
|
if (depthAttachment.view != nullptr
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
#include "dxvk_data.h"
|
#include "dxvk_data.h"
|
||||||
#include "dxvk_event.h"
|
#include "dxvk_event.h"
|
||||||
#include "dxvk_meta_clear.h"
|
#include "dxvk_meta_clear.h"
|
||||||
|
#include "dxvk_meta_mipgen.h"
|
||||||
#include "dxvk_meta_resolve.h"
|
#include "dxvk_meta_resolve.h"
|
||||||
#include "dxvk_pipecache.h"
|
#include "dxvk_pipecache.h"
|
||||||
#include "dxvk_pipemanager.h"
|
#include "dxvk_pipemanager.h"
|
||||||
@ -28,9 +29,10 @@ namespace dxvk {
|
|||||||
public:
|
public:
|
||||||
|
|
||||||
DxvkContext(
|
DxvkContext(
|
||||||
const Rc<DxvkDevice>& device,
|
const Rc<DxvkDevice>& device,
|
||||||
const Rc<DxvkPipelineManager>& pipelineManager,
|
const Rc<DxvkPipelineManager>& pipelineManager,
|
||||||
const Rc<DxvkMetaClearObjects>& metaClearObjects);
|
const Rc<DxvkMetaClearObjects>& metaClearObjects,
|
||||||
|
const Rc<DxvkMetaMipGenObjects>& metaMipGenObjects);
|
||||||
~DxvkContext();
|
~DxvkContext();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -403,12 +405,10 @@ namespace dxvk {
|
|||||||
*
|
*
|
||||||
* Uses blitting to generate lower mip levels from
|
* Uses blitting to generate lower mip levels from
|
||||||
* the top-most mip level passed to this method.
|
* the top-most mip level passed to this method.
|
||||||
* \param [in] image The image to generate mips for
|
* \param [in] imageView The image to generate mips for
|
||||||
* \param [in] subresource The subresource range
|
|
||||||
*/
|
*/
|
||||||
void generateMipmaps(
|
void generateMipmaps(
|
||||||
const Rc<DxvkImage>& image,
|
const Rc<DxvkImageView>& imageView);
|
||||||
const VkImageSubresourceRange& subresources);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Initializes or invalidates an image
|
* \brief Initializes or invalidates an image
|
||||||
@ -621,6 +621,7 @@ namespace dxvk {
|
|||||||
const Rc<DxvkDevice> m_device;
|
const Rc<DxvkDevice> m_device;
|
||||||
const Rc<DxvkPipelineManager> m_pipeMgr;
|
const Rc<DxvkPipelineManager> m_pipeMgr;
|
||||||
const Rc<DxvkMetaClearObjects> m_metaClear;
|
const Rc<DxvkMetaClearObjects> m_metaClear;
|
||||||
|
const Rc<DxvkMetaMipGenObjects> m_metaMipGen;
|
||||||
|
|
||||||
Rc<DxvkCommandList> m_cmd;
|
Rc<DxvkCommandList> m_cmd;
|
||||||
DxvkContextFlags m_flags;
|
DxvkContextFlags m_flags;
|
||||||
@ -654,10 +655,10 @@ namespace dxvk {
|
|||||||
DxvkRenderPassOps& renderPassOps);
|
DxvkRenderPassOps& renderPassOps);
|
||||||
|
|
||||||
void unbindComputePipeline();
|
void unbindComputePipeline();
|
||||||
|
|
||||||
void updateComputePipeline();
|
void updateComputePipeline();
|
||||||
void updateComputePipelineState();
|
void updateComputePipelineState();
|
||||||
|
|
||||||
|
void unbindGraphicsPipeline();
|
||||||
void updateGraphicsPipeline();
|
void updateGraphicsPipeline();
|
||||||
void updateGraphicsPipelineState();
|
void updateGraphicsPipelineState();
|
||||||
|
|
||||||
|
@ -8,17 +8,18 @@ namespace dxvk {
|
|||||||
const Rc<vk::DeviceFn>& vkd,
|
const Rc<vk::DeviceFn>& vkd,
|
||||||
const Rc<DxvkDeviceExtensions>& extensions,
|
const Rc<DxvkDeviceExtensions>& extensions,
|
||||||
const VkPhysicalDeviceFeatures& features)
|
const VkPhysicalDeviceFeatures& features)
|
||||||
: m_adapter (adapter),
|
: m_adapter (adapter),
|
||||||
m_vkd (vkd),
|
m_vkd (vkd),
|
||||||
m_extensions (extensions),
|
m_extensions (extensions),
|
||||||
m_features (features),
|
m_features (features),
|
||||||
m_properties (adapter->deviceProperties()),
|
m_properties (adapter->deviceProperties()),
|
||||||
m_memory (new DxvkMemoryAllocator (adapter, vkd)),
|
m_memory (new DxvkMemoryAllocator (adapter, vkd)),
|
||||||
m_renderPassPool (new DxvkRenderPassPool (vkd)),
|
m_renderPassPool (new DxvkRenderPassPool (vkd)),
|
||||||
m_pipelineManager (new DxvkPipelineManager (this)),
|
m_pipelineManager (new DxvkPipelineManager (this)),
|
||||||
m_metaClearObjects(new DxvkMetaClearObjects (vkd)),
|
m_metaClearObjects (new DxvkMetaClearObjects (vkd)),
|
||||||
m_unboundResources(this),
|
m_metaMipGenObjects (new DxvkMetaMipGenObjects(vkd)),
|
||||||
m_submissionQueue (this) {
|
m_unboundResources (this),
|
||||||
|
m_submissionQueue (this) {
|
||||||
m_graphicsQueue.queueFamily = m_adapter->graphicsQueueFamily();
|
m_graphicsQueue.queueFamily = m_adapter->graphicsQueueFamily();
|
||||||
m_presentQueue.queueFamily = m_adapter->presentQueueFamily();
|
m_presentQueue.queueFamily = m_adapter->presentQueueFamily();
|
||||||
|
|
||||||
@ -106,7 +107,8 @@ namespace dxvk {
|
|||||||
Rc<DxvkContext> DxvkDevice::createContext() {
|
Rc<DxvkContext> DxvkDevice::createContext() {
|
||||||
return new DxvkContext(this,
|
return new DxvkContext(this,
|
||||||
m_pipelineManager,
|
m_pipelineManager,
|
||||||
m_metaClearObjects);
|
m_metaClearObjects,
|
||||||
|
m_metaMipGenObjects);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -356,6 +356,7 @@ namespace dxvk {
|
|||||||
Rc<DxvkRenderPassPool> m_renderPassPool;
|
Rc<DxvkRenderPassPool> m_renderPassPool;
|
||||||
Rc<DxvkPipelineManager> m_pipelineManager;
|
Rc<DxvkPipelineManager> m_pipelineManager;
|
||||||
Rc<DxvkMetaClearObjects> m_metaClearObjects;
|
Rc<DxvkMetaClearObjects> m_metaClearObjects;
|
||||||
|
Rc<DxvkMetaMipGenObjects> m_metaMipGenObjects;
|
||||||
|
|
||||||
DxvkUnboundResources m_unboundResources;
|
DxvkUnboundResources m_unboundResources;
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include "dxvk_device.h"
|
#include "dxvk_device.h"
|
||||||
#include "dxvk_graphics.h"
|
#include "dxvk_graphics.h"
|
||||||
|
#include "dxvk_spec_const.h"
|
||||||
|
|
||||||
namespace dxvk {
|
namespace dxvk {
|
||||||
|
|
||||||
@ -203,19 +204,17 @@ namespace dxvk {
|
|||||||
VK_DYNAMIC_STATE_STENCIL_REFERENCE,
|
VK_DYNAMIC_STATE_STENCIL_REFERENCE,
|
||||||
};
|
};
|
||||||
|
|
||||||
std::array<VkBool32, MaxNumActiveBindings> specData;
|
DxvkSpecConstantData specData;
|
||||||
std::array<VkSpecializationMapEntry, MaxNumActiveBindings> specMap;
|
specData.rasterizerSampleCount = uint32_t(state.msSampleCount);
|
||||||
|
|
||||||
for (uint32_t i = 0; i < MaxNumActiveBindings; i++) {
|
for (uint32_t i = 0; i < MaxNumActiveBindings; i++)
|
||||||
specData[i] = state.bsBindingState.isBound(i) ? VK_TRUE : VK_FALSE;
|
specData.activeBindings[i] = state.bsBindingState.isBound(i) ? VK_TRUE : VK_FALSE;
|
||||||
specMap [i] = { i, static_cast<uint32_t>(sizeof(VkBool32)) * i, sizeof(VkBool32) };
|
|
||||||
}
|
|
||||||
|
|
||||||
VkSpecializationInfo specInfo;
|
VkSpecializationInfo specInfo;
|
||||||
specInfo.mapEntryCount = specMap.size();
|
specInfo.mapEntryCount = g_specConstantMap.mapEntryCount();
|
||||||
specInfo.pMapEntries = specMap.data();
|
specInfo.pMapEntries = g_specConstantMap.mapEntryData();
|
||||||
specInfo.dataSize = specData.size() * sizeof(VkBool32);
|
specInfo.dataSize = sizeof(specData);
|
||||||
specInfo.pData = specData.data();
|
specInfo.pData = &specData;
|
||||||
|
|
||||||
std::vector<VkPipelineShaderStageCreateInfo> stages;
|
std::vector<VkPipelineShaderStageCreateInfo> stages;
|
||||||
|
|
||||||
|
@ -4,6 +4,13 @@
|
|||||||
|
|
||||||
namespace dxvk {
|
namespace dxvk {
|
||||||
|
|
||||||
|
struct DxvkEq {
|
||||||
|
template<typename T>
|
||||||
|
size_t operator () (const T& a, const T& b) const {
|
||||||
|
return a.eq(b);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
struct DxvkHash {
|
struct DxvkHash {
|
||||||
template<typename T>
|
template<typename T>
|
||||||
size_t operator () (const T& object) const {
|
size_t operator () (const T& object) const {
|
||||||
|
@ -87,25 +87,75 @@ namespace dxvk {
|
|||||||
const Rc<DxvkImage>& image,
|
const Rc<DxvkImage>& image,
|
||||||
const DxvkImageViewCreateInfo& info)
|
const DxvkImageViewCreateInfo& info)
|
||||||
: m_vkd(vkd), m_image(image), m_info(info) {
|
: m_vkd(vkd), m_image(image), m_info(info) {
|
||||||
|
// Since applications tend to bind views
|
||||||
|
for (uint32_t i = 0; i < ViewCount; i++)
|
||||||
|
m_views[i] = VK_NULL_HANDLE;
|
||||||
|
|
||||||
|
switch (info.type) {
|
||||||
|
case VK_IMAGE_VIEW_TYPE_1D:
|
||||||
|
case VK_IMAGE_VIEW_TYPE_1D_ARRAY: {
|
||||||
|
this->createView(VK_IMAGE_VIEW_TYPE_1D, 1);
|
||||||
|
this->createView(VK_IMAGE_VIEW_TYPE_1D_ARRAY, info.numLayers);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case VK_IMAGE_VIEW_TYPE_2D:
|
||||||
|
case VK_IMAGE_VIEW_TYPE_2D_ARRAY:
|
||||||
|
case VK_IMAGE_VIEW_TYPE_CUBE:
|
||||||
|
case VK_IMAGE_VIEW_TYPE_CUBE_ARRAY: {
|
||||||
|
this->createView(VK_IMAGE_VIEW_TYPE_2D, 1);
|
||||||
|
this->createView(VK_IMAGE_VIEW_TYPE_2D_ARRAY, info.numLayers);
|
||||||
|
|
||||||
|
if (m_image->info().flags & VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT) {
|
||||||
|
uint32_t cubeCount = info.numLayers / 6;
|
||||||
|
|
||||||
|
if (cubeCount > 0) {
|
||||||
|
this->createView(VK_IMAGE_VIEW_TYPE_CUBE, 6);
|
||||||
|
this->createView(VK_IMAGE_VIEW_TYPE_CUBE_ARRAY, 6 * cubeCount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case VK_IMAGE_VIEW_TYPE_3D: {
|
||||||
|
this->createView(VK_IMAGE_VIEW_TYPE_3D, 1);
|
||||||
|
|
||||||
|
if (m_image->info().flags & VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT_KHR) {
|
||||||
|
this->createView(VK_IMAGE_VIEW_TYPE_2D, 1);
|
||||||
|
this->createView(VK_IMAGE_VIEW_TYPE_2D_ARRAY, m_image->info().extent.depth);
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw DxvkError(str::format("DxvkImageView: Invalid view type: ", info.type));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DxvkImageView::~DxvkImageView() {
|
||||||
|
for (uint32_t i = 0; i < ViewCount; i++)
|
||||||
|
m_vkd->vkDestroyImageView(m_vkd->device(), m_views[i], nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void DxvkImageView::createView(VkImageViewType type, uint32_t numLayers) {
|
||||||
VkImageSubresourceRange subresourceRange;
|
VkImageSubresourceRange subresourceRange;
|
||||||
subresourceRange.aspectMask = info.aspect;
|
subresourceRange.aspectMask = m_info.aspect;
|
||||||
subresourceRange.baseMipLevel = info.minLevel;
|
subresourceRange.baseMipLevel = m_info.minLevel;
|
||||||
subresourceRange.levelCount = info.numLevels;
|
subresourceRange.levelCount = m_info.numLevels;
|
||||||
subresourceRange.baseArrayLayer = info.minLayer;
|
subresourceRange.baseArrayLayer = m_info.minLayer;
|
||||||
subresourceRange.layerCount = info.numLayers;
|
subresourceRange.layerCount = numLayers;
|
||||||
|
|
||||||
VkImageViewCreateInfo viewInfo;
|
VkImageViewCreateInfo viewInfo;
|
||||||
viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
||||||
viewInfo.pNext = nullptr;
|
viewInfo.pNext = nullptr;
|
||||||
viewInfo.flags = 0;
|
viewInfo.flags = 0;
|
||||||
viewInfo.image = image->handle();
|
viewInfo.image = m_image->handle();
|
||||||
viewInfo.viewType = info.type;
|
viewInfo.viewType = type;
|
||||||
viewInfo.format = info.format;
|
viewInfo.format = m_info.format;
|
||||||
viewInfo.components = info.swizzle;
|
viewInfo.components = m_info.swizzle;
|
||||||
viewInfo.subresourceRange = subresourceRange;
|
viewInfo.subresourceRange = subresourceRange;
|
||||||
|
|
||||||
if (m_vkd->vkCreateImageView(m_vkd->device(),
|
if (m_vkd->vkCreateImageView(m_vkd->device(),
|
||||||
&viewInfo, nullptr, &m_view) != VK_SUCCESS) {
|
&viewInfo, nullptr, &m_views[type]) != VK_SUCCESS) {
|
||||||
throw DxvkError(str::format(
|
throw DxvkError(str::format(
|
||||||
"DxvkImageView: Failed to create image view:"
|
"DxvkImageView: Failed to create image view:"
|
||||||
"\n View type: ", viewInfo.viewType,
|
"\n View type: ", viewInfo.viewType,
|
||||||
@ -117,23 +167,17 @@ namespace dxvk {
|
|||||||
"\n Array layers: ", viewInfo.subresourceRange.baseArrayLayer, " - ",
|
"\n Array layers: ", viewInfo.subresourceRange.baseArrayLayer, " - ",
|
||||||
viewInfo.subresourceRange.layerCount,
|
viewInfo.subresourceRange.layerCount,
|
||||||
"\n Image properties:",
|
"\n Image properties:",
|
||||||
"\n Type: ", image->info().type,
|
"\n Type: ", m_image->info().type,
|
||||||
"\n Format: ", image->info().format,
|
"\n Format: ", m_image->info().format,
|
||||||
"\n Extent: ", "(", image->info().extent.width,
|
"\n Extent: ", "(", m_image->info().extent.width,
|
||||||
",", image->info().extent.height,
|
",", m_image->info().extent.height,
|
||||||
",", image->info().extent.depth, ")",
|
",", m_image->info().extent.depth, ")",
|
||||||
"\n Mip levels: ", image->info().mipLevels,
|
"\n Mip levels: ", m_image->info().mipLevels,
|
||||||
"\n Array layers: ", image->info().numLayers,
|
"\n Array layers: ", m_image->info().numLayers,
|
||||||
"\n Samples: ", image->info().sampleCount,
|
"\n Samples: ", m_image->info().sampleCount,
|
||||||
"\n Usage: ", std::hex, image->info().usage,
|
"\n Usage: ", std::hex, m_image->info().usage,
|
||||||
"\n Tiling: ", image->info().tiling));
|
"\n Tiling: ", m_image->info().tiling));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
DxvkImageView::~DxvkImageView() {
|
|
||||||
m_vkd->vkDestroyImageView(
|
|
||||||
m_vkd->device(), m_view, nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
@ -232,7 +232,7 @@ namespace dxvk {
|
|||||||
* \brief DXVK image view
|
* \brief DXVK image view
|
||||||
*/
|
*/
|
||||||
class DxvkImageView : public DxvkResource {
|
class DxvkImageView : public DxvkResource {
|
||||||
|
constexpr static uint32_t ViewCount = VK_IMAGE_VIEW_TYPE_CUBE_ARRAY + 1;
|
||||||
public:
|
public:
|
||||||
|
|
||||||
DxvkImageView(
|
DxvkImageView(
|
||||||
@ -243,21 +243,34 @@ namespace dxvk {
|
|||||||
~DxvkImageView();
|
~DxvkImageView();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Image view handle
|
* \brief Image view handle for the default type
|
||||||
*
|
*
|
||||||
* Internal use only.
|
* The default view type is guaranteed to be
|
||||||
|
* supported by the image view, and should be
|
||||||
|
* preferred over picking a different type.
|
||||||
* \returns Image view handle
|
* \returns Image view handle
|
||||||
*/
|
*/
|
||||||
VkImageView handle() const {
|
VkImageView handle() const {
|
||||||
return m_view;
|
return handle(m_info.type);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Image view handle for a given view type
|
||||||
|
*
|
||||||
|
* If the view does not support the requested image
|
||||||
|
* view type, \c VK_NULL_HANDLE will be returned.
|
||||||
|
* \param [in] viewType The requested view type
|
||||||
|
* \returns The image view handle
|
||||||
|
*/
|
||||||
|
VkImageView handle(VkImageViewType viewType) const {
|
||||||
|
return m_views[viewType];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Image view type
|
* \brief Image view type
|
||||||
*
|
*
|
||||||
* Convenience method to query the
|
* Convenience method to query the view type
|
||||||
* view type in order to check for
|
* in order to check for resource compatibility.
|
||||||
* resource compatibility.
|
|
||||||
* \returns Image view type
|
* \returns Image view type
|
||||||
*/
|
*/
|
||||||
VkImageViewType type() const {
|
VkImageViewType type() const {
|
||||||
@ -272,6 +285,14 @@ namespace dxvk {
|
|||||||
return m_info;
|
return m_info;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Image handle
|
||||||
|
* \returns Image handle
|
||||||
|
*/
|
||||||
|
VkImage imageHandle() const {
|
||||||
|
return m_image->handle();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Image properties
|
* \brief Image properties
|
||||||
* \returns Image properties
|
* \returns Image properties
|
||||||
@ -289,8 +310,8 @@ namespace dxvk {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Image
|
* \brief Image object
|
||||||
* \returns Image
|
* \returns Image object
|
||||||
*/
|
*/
|
||||||
Rc<DxvkImage> image() const {
|
Rc<DxvkImage> image() const {
|
||||||
return m_image;
|
return m_image;
|
||||||
@ -336,7 +357,9 @@ namespace dxvk {
|
|||||||
Rc<DxvkImage> m_image;
|
Rc<DxvkImage> m_image;
|
||||||
|
|
||||||
DxvkImageViewCreateInfo m_info;
|
DxvkImageViewCreateInfo m_info;
|
||||||
VkImageView m_view;
|
VkImageView m_views[ViewCount];
|
||||||
|
|
||||||
|
void createView(VkImageViewType type, uint32_t numLayers);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
554
src/dxvk/dxvk_meta_mipgen.cpp
Normal file
554
src/dxvk/dxvk_meta_mipgen.cpp
Normal file
@ -0,0 +1,554 @@
|
|||||||
|
#include "dxvk_meta_mipgen.h"
|
||||||
|
|
||||||
|
#include <dxvk_mipgen_vert.h>
|
||||||
|
#include <dxvk_mipgen_geom.h>
|
||||||
|
#include <dxvk_mipgen_frag_1d.h>
|
||||||
|
#include <dxvk_mipgen_frag_2d.h>
|
||||||
|
#include <dxvk_mipgen_frag_3d.h>
|
||||||
|
|
||||||
|
namespace dxvk {
|
||||||
|
|
||||||
|
DxvkMetaMipGenRenderPass::DxvkMetaMipGenRenderPass(
|
||||||
|
const Rc<vk::DeviceFn>& vkd,
|
||||||
|
const Rc<DxvkImageView>& view)
|
||||||
|
: m_vkd(vkd), m_view(view), m_renderPass(createRenderPass()) {
|
||||||
|
// Determine view type based on image type
|
||||||
|
const std::array<std::pair<VkImageViewType, VkImageViewType>, 3> viewTypes = {{
|
||||||
|
{ VK_IMAGE_VIEW_TYPE_1D_ARRAY, VK_IMAGE_VIEW_TYPE_1D_ARRAY },
|
||||||
|
{ VK_IMAGE_VIEW_TYPE_2D_ARRAY, VK_IMAGE_VIEW_TYPE_2D_ARRAY },
|
||||||
|
{ VK_IMAGE_VIEW_TYPE_3D, VK_IMAGE_VIEW_TYPE_2D_ARRAY },
|
||||||
|
}};
|
||||||
|
|
||||||
|
m_srcViewType = viewTypes.at(uint32_t(view->imageInfo().type)).first;
|
||||||
|
m_dstViewType = viewTypes.at(uint32_t(view->imageInfo().type)).second;
|
||||||
|
|
||||||
|
// Create image views and framebuffers
|
||||||
|
m_passes.resize(view->info().numLevels - 1);
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < m_passes.size(); i++)
|
||||||
|
m_passes.at(i) = this->createFramebuffer(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DxvkMetaMipGenRenderPass::~DxvkMetaMipGenRenderPass() {
|
||||||
|
for (const auto& pass : m_passes) {
|
||||||
|
m_vkd->vkDestroyFramebuffer(m_vkd->device(), pass.framebuffer, nullptr);
|
||||||
|
m_vkd->vkDestroyImageView(m_vkd->device(), pass.dstView, nullptr);
|
||||||
|
m_vkd->vkDestroyImageView(m_vkd->device(), pass.srcView, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_vkd->vkDestroyRenderPass(m_vkd->device(), m_renderPass, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
VkExtent3D DxvkMetaMipGenRenderPass::passExtent(uint32_t passId) const {
|
||||||
|
VkExtent3D extent = m_view->mipLevelExtent(passId + 1);
|
||||||
|
|
||||||
|
if (m_view->imageInfo().type != VK_IMAGE_TYPE_3D)
|
||||||
|
extent.depth = m_view->info().numLayers;
|
||||||
|
|
||||||
|
return extent;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
VkRenderPass DxvkMetaMipGenRenderPass::createRenderPass() const {
|
||||||
|
std::array<VkSubpassDependency, 2> subpassDeps = {{
|
||||||
|
{ VK_SUBPASS_EXTERNAL, 0,
|
||||||
|
m_view->imageInfo().stages,
|
||||||
|
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
|
||||||
|
m_view->imageInfo().access,
|
||||||
|
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
|
||||||
|
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, 0 },
|
||||||
|
{ 0, VK_SUBPASS_EXTERNAL,
|
||||||
|
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
|
||||||
|
m_view->imageInfo().stages,
|
||||||
|
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
|
||||||
|
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
|
||||||
|
m_view->imageInfo().access, 0 },
|
||||||
|
}};
|
||||||
|
|
||||||
|
VkAttachmentDescription attachment;
|
||||||
|
attachment.flags = 0;
|
||||||
|
attachment.format = m_view->info().format;
|
||||||
|
attachment.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||||
|
attachment.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||||
|
attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||||
|
attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||||
|
attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
||||||
|
attachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||||
|
attachment.finalLayout = m_view->imageInfo().layout;
|
||||||
|
|
||||||
|
VkAttachmentReference attachmentRef;
|
||||||
|
attachmentRef.attachment = 0;
|
||||||
|
attachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||||
|
|
||||||
|
VkSubpassDescription subpass;
|
||||||
|
subpass.flags = 0;
|
||||||
|
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
|
||||||
|
subpass.inputAttachmentCount = 0;
|
||||||
|
subpass.pInputAttachments = nullptr;
|
||||||
|
subpass.colorAttachmentCount = 1;
|
||||||
|
subpass.pColorAttachments = &attachmentRef;
|
||||||
|
subpass.pResolveAttachments = nullptr;
|
||||||
|
subpass.pDepthStencilAttachment = nullptr;
|
||||||
|
subpass.preserveAttachmentCount = 0;
|
||||||
|
subpass.pPreserveAttachments = nullptr;
|
||||||
|
|
||||||
|
VkRenderPassCreateInfo info;
|
||||||
|
info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
|
||||||
|
info.pNext = nullptr;
|
||||||
|
info.flags = 0;
|
||||||
|
info.attachmentCount = 1;
|
||||||
|
info.pAttachments = &attachment;
|
||||||
|
info.subpassCount = 1;
|
||||||
|
info.pSubpasses = &subpass;
|
||||||
|
info.dependencyCount = subpassDeps.size();
|
||||||
|
info.pDependencies = subpassDeps.data();
|
||||||
|
|
||||||
|
VkRenderPass result = VK_NULL_HANDLE;
|
||||||
|
if (m_vkd->vkCreateRenderPass(m_vkd->device(), &info, nullptr, &result) != VK_SUCCESS)
|
||||||
|
throw DxvkError("DxvkMetaMipGenRenderPass: Failed to create render pass");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DxvkMetaMipGenPass DxvkMetaMipGenRenderPass::createFramebuffer(uint32_t pass) const {
|
||||||
|
DxvkMetaMipGenPass result;
|
||||||
|
result.srcView = VK_NULL_HANDLE;
|
||||||
|
result.dstView = VK_NULL_HANDLE;
|
||||||
|
result.framebuffer = VK_NULL_HANDLE;
|
||||||
|
|
||||||
|
// Common image view info
|
||||||
|
VkImageViewCreateInfo viewInfo;
|
||||||
|
viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
||||||
|
viewInfo.pNext = nullptr;
|
||||||
|
viewInfo.flags = 0;
|
||||||
|
viewInfo.image = m_view->imageHandle();
|
||||||
|
viewInfo.format = m_view->info().format;
|
||||||
|
viewInfo.components = {
|
||||||
|
VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY,
|
||||||
|
VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY };
|
||||||
|
|
||||||
|
// Create source image view, which points to
|
||||||
|
// the one mip level we're going to sample.
|
||||||
|
VkImageSubresourceRange srcSubresources;
|
||||||
|
srcSubresources.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||||
|
srcSubresources.baseMipLevel = m_view->info().minLevel + pass;
|
||||||
|
srcSubresources.levelCount = 1;
|
||||||
|
srcSubresources.baseArrayLayer = m_view->info().minLayer;
|
||||||
|
srcSubresources.layerCount = m_view->info().numLayers;
|
||||||
|
|
||||||
|
viewInfo.viewType = m_srcViewType;
|
||||||
|
viewInfo.subresourceRange = srcSubresources;
|
||||||
|
|
||||||
|
if (m_vkd->vkCreateImageView(m_vkd->device(), &viewInfo, nullptr, &result.srcView) != VK_SUCCESS)
|
||||||
|
throw DxvkError("DxvkMetaMipGenRenderPass: Failed to create source image view");
|
||||||
|
|
||||||
|
// Create destination image view, which points
|
||||||
|
// to the mip level we're going to render to.
|
||||||
|
VkExtent3D dstExtent = m_view->mipLevelExtent(pass + 1);
|
||||||
|
|
||||||
|
VkImageSubresourceRange dstSubresources;
|
||||||
|
dstSubresources.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||||
|
dstSubresources.baseMipLevel = m_view->info().minLevel + pass + 1;
|
||||||
|
dstSubresources.levelCount = 1;
|
||||||
|
|
||||||
|
if (m_view->imageInfo().type != VK_IMAGE_TYPE_3D) {
|
||||||
|
dstSubresources.baseArrayLayer = m_view->info().minLayer;
|
||||||
|
dstSubresources.layerCount = m_view->info().numLayers;
|
||||||
|
} else {
|
||||||
|
dstSubresources.baseArrayLayer = 0;
|
||||||
|
dstSubresources.layerCount = dstExtent.depth;
|
||||||
|
}
|
||||||
|
|
||||||
|
viewInfo.viewType = m_dstViewType;
|
||||||
|
viewInfo.subresourceRange = dstSubresources;
|
||||||
|
|
||||||
|
if (m_vkd->vkCreateImageView(m_vkd->device(), &viewInfo, nullptr, &result.dstView) != VK_SUCCESS)
|
||||||
|
throw DxvkError("DxvkMetaMipGenRenderPass: Failed to create target image view");
|
||||||
|
|
||||||
|
// Create framebuffer using the destination
|
||||||
|
// image view as its color attachment.
|
||||||
|
VkFramebufferCreateInfo fboInfo;
|
||||||
|
fboInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
|
||||||
|
fboInfo.pNext = nullptr;
|
||||||
|
fboInfo.flags = 0;
|
||||||
|
fboInfo.renderPass = m_renderPass;
|
||||||
|
fboInfo.attachmentCount = 1;
|
||||||
|
fboInfo.pAttachments = &result.dstView;
|
||||||
|
fboInfo.width = dstExtent.width;
|
||||||
|
fboInfo.height = dstExtent.height;
|
||||||
|
fboInfo.layers = dstSubresources.layerCount;
|
||||||
|
|
||||||
|
if (m_vkd->vkCreateFramebuffer(m_vkd->device(), &fboInfo, nullptr, &result.framebuffer) != VK_SUCCESS)
|
||||||
|
throw DxvkError("DxvkMetaMipGenRenderPass: Failed to create target framebuffer");
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DxvkMetaMipGenObjects::DxvkMetaMipGenObjects(const Rc<vk::DeviceFn>& vkd)
|
||||||
|
: m_vkd (vkd),
|
||||||
|
m_sampler (createSampler()),
|
||||||
|
m_shaderVert (createShaderModule(dxvk_mipgen_vert)),
|
||||||
|
m_shaderGeom (createShaderModule(dxvk_mipgen_geom)),
|
||||||
|
m_shaderFrag1D(createShaderModule(dxvk_mipgen_frag_1d)),
|
||||||
|
m_shaderFrag2D(createShaderModule(dxvk_mipgen_frag_2d)),
|
||||||
|
m_shaderFrag3D(createShaderModule(dxvk_mipgen_frag_3d)) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DxvkMetaMipGenObjects::~DxvkMetaMipGenObjects() {
|
||||||
|
for (const auto& pair : m_renderPasses)
|
||||||
|
m_vkd->vkDestroyRenderPass(m_vkd->device(), pair.second, nullptr);
|
||||||
|
|
||||||
|
for (const auto& pair : m_pipelines) {
|
||||||
|
m_vkd->vkDestroyPipeline(m_vkd->device(), pair.second.pipeHandle, nullptr);
|
||||||
|
m_vkd->vkDestroyPipelineLayout(m_vkd->device(), pair.second.pipeLayout, nullptr);
|
||||||
|
m_vkd->vkDestroyDescriptorSetLayout (m_vkd->device(), pair.second.dsetLayout, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_vkd->vkDestroyShaderModule(m_vkd->device(), m_shaderFrag3D, nullptr);
|
||||||
|
m_vkd->vkDestroyShaderModule(m_vkd->device(), m_shaderFrag2D, nullptr);
|
||||||
|
m_vkd->vkDestroyShaderModule(m_vkd->device(), m_shaderFrag1D, nullptr);
|
||||||
|
m_vkd->vkDestroyShaderModule(m_vkd->device(), m_shaderGeom, nullptr);
|
||||||
|
m_vkd->vkDestroyShaderModule(m_vkd->device(), m_shaderVert, nullptr);
|
||||||
|
|
||||||
|
m_vkd->vkDestroySampler(m_vkd->device(), m_sampler, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DxvkMetaMipGenPipeline DxvkMetaMipGenObjects::getPipeline(
|
||||||
|
VkImageViewType viewType,
|
||||||
|
VkFormat viewFormat) {
|
||||||
|
std::lock_guard<std::mutex> lock(m_mutex);
|
||||||
|
|
||||||
|
DxvkMetaMipGenPipelineKey key;
|
||||||
|
key.viewType = viewType;
|
||||||
|
key.viewFormat = viewFormat;
|
||||||
|
|
||||||
|
auto entry = m_pipelines.find(key);
|
||||||
|
if (entry != m_pipelines.end())
|
||||||
|
return entry->second;
|
||||||
|
|
||||||
|
DxvkMetaMipGenPipeline pipeline = this->createPipeline(key);
|
||||||
|
m_pipelines.insert({ key, pipeline });
|
||||||
|
return pipeline;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
VkRenderPass DxvkMetaMipGenObjects::getRenderPass(VkFormat viewFormat) {
|
||||||
|
auto entry = m_renderPasses.find(viewFormat);
|
||||||
|
if (entry != m_renderPasses.end())
|
||||||
|
return entry->second;
|
||||||
|
|
||||||
|
VkRenderPass renderPass = this->createRenderPass(viewFormat);
|
||||||
|
m_renderPasses.insert({ viewFormat, renderPass });
|
||||||
|
return renderPass;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
VkSampler DxvkMetaMipGenObjects::createSampler() const {
|
||||||
|
VkSamplerCreateInfo info;
|
||||||
|
info.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
|
||||||
|
info.pNext = nullptr;
|
||||||
|
info.flags = 0;
|
||||||
|
info.magFilter = VK_FILTER_LINEAR;
|
||||||
|
info.minFilter = VK_FILTER_LINEAR;
|
||||||
|
info.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST;
|
||||||
|
info.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
||||||
|
info.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
||||||
|
info.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
||||||
|
info.mipLodBias = 0.0f;
|
||||||
|
info.anisotropyEnable = VK_FALSE;
|
||||||
|
info.maxAnisotropy = 1.0f;
|
||||||
|
info.compareEnable = VK_FALSE;
|
||||||
|
info.compareOp = VK_COMPARE_OP_ALWAYS;
|
||||||
|
info.minLod = 0.0f;
|
||||||
|
info.maxLod = 0.0f;
|
||||||
|
info.borderColor = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK;
|
||||||
|
info.unnormalizedCoordinates = VK_FALSE;
|
||||||
|
|
||||||
|
VkSampler result = VK_NULL_HANDLE;
|
||||||
|
if (m_vkd->vkCreateSampler(m_vkd->device(), &info, nullptr, &result) != VK_SUCCESS)
|
||||||
|
throw DxvkError("DxvkMetaMipGenObjects: Failed to create sampler");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
VkShaderModule DxvkMetaMipGenObjects::createShaderModule(const SpirvCodeBuffer& code) const {
|
||||||
|
VkShaderModuleCreateInfo info;
|
||||||
|
info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
|
||||||
|
info.pNext = nullptr;
|
||||||
|
info.flags = 0;
|
||||||
|
info.codeSize = code.size();
|
||||||
|
info.pCode = code.data();
|
||||||
|
|
||||||
|
VkShaderModule result = VK_NULL_HANDLE;
|
||||||
|
if (m_vkd->vkCreateShaderModule(m_vkd->device(), &info, nullptr, &result) != VK_SUCCESS)
|
||||||
|
throw DxvkError("DxvkMetaMipGenObjects: Failed to create shader module");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DxvkMetaMipGenPipeline DxvkMetaMipGenObjects::createPipeline(
|
||||||
|
const DxvkMetaMipGenPipelineKey& key) {
|
||||||
|
DxvkMetaMipGenPipeline pipe;
|
||||||
|
pipe.dsetLayout = this->createDescriptorSetLayout(key.viewType);
|
||||||
|
pipe.pipeLayout = this->createPipelineLayout(pipe.dsetLayout);
|
||||||
|
pipe.pipeHandle = this->createPipeline(key.viewType, pipe.pipeLayout,
|
||||||
|
this->getRenderPass(key.viewFormat));
|
||||||
|
return pipe;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
VkRenderPass DxvkMetaMipGenObjects::createRenderPass(
|
||||||
|
VkFormat format) const {
|
||||||
|
VkAttachmentDescription attachment;
|
||||||
|
attachment.flags = 0;
|
||||||
|
attachment.format = format;
|
||||||
|
attachment.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||||
|
attachment.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||||
|
attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||||
|
attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||||
|
attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
||||||
|
attachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||||
|
attachment.finalLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||||
|
|
||||||
|
VkAttachmentReference attachmentRef;
|
||||||
|
attachmentRef.attachment = 0;
|
||||||
|
attachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||||
|
|
||||||
|
VkSubpassDescription subpass;
|
||||||
|
subpass.flags = 0;
|
||||||
|
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
|
||||||
|
subpass.inputAttachmentCount = 0;
|
||||||
|
subpass.pInputAttachments = nullptr;
|
||||||
|
subpass.colorAttachmentCount = 1;
|
||||||
|
subpass.pColorAttachments = &attachmentRef;
|
||||||
|
subpass.pResolveAttachments = nullptr;
|
||||||
|
subpass.pDepthStencilAttachment = nullptr;
|
||||||
|
subpass.preserveAttachmentCount = 0;
|
||||||
|
subpass.pPreserveAttachments = nullptr;
|
||||||
|
|
||||||
|
VkRenderPassCreateInfo info;
|
||||||
|
info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
|
||||||
|
info.pNext = nullptr;
|
||||||
|
info.flags = 0;
|
||||||
|
info.attachmentCount = 1;
|
||||||
|
info.pAttachments = &attachment;
|
||||||
|
info.subpassCount = 1;
|
||||||
|
info.pSubpasses = &subpass;
|
||||||
|
info.dependencyCount = 0;
|
||||||
|
info.pDependencies = nullptr;
|
||||||
|
|
||||||
|
VkRenderPass result = VK_NULL_HANDLE;
|
||||||
|
if (m_vkd->vkCreateRenderPass(m_vkd->device(), &info, nullptr, &result) != VK_SUCCESS)
|
||||||
|
throw DxvkError("DxvkMetaMipGenObjects: Failed to create render pass");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
VkDescriptorSetLayout DxvkMetaMipGenObjects::createDescriptorSetLayout(
|
||||||
|
VkImageViewType viewType) const {
|
||||||
|
VkDescriptorSetLayoutBinding binding;
|
||||||
|
binding.binding = 0;
|
||||||
|
binding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||||
|
binding.descriptorCount = 1;
|
||||||
|
binding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||||
|
binding.pImmutableSamplers = &m_sampler;
|
||||||
|
|
||||||
|
VkDescriptorSetLayoutCreateInfo info;
|
||||||
|
info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
|
||||||
|
info.pNext = nullptr;
|
||||||
|
info.flags = 0;
|
||||||
|
info.bindingCount = 1;
|
||||||
|
info.pBindings = &binding;
|
||||||
|
|
||||||
|
VkDescriptorSetLayout result = VK_NULL_HANDLE;
|
||||||
|
if (m_vkd->vkCreateDescriptorSetLayout(m_vkd->device(), &info, nullptr, &result) != VK_SUCCESS)
|
||||||
|
throw DxvkError("DxvkMetaMipGenObjects: Failed to create descriptor set layout");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
VkPipelineLayout DxvkMetaMipGenObjects::createPipelineLayout(
|
||||||
|
VkDescriptorSetLayout descriptorSetLayout) const {
|
||||||
|
VkPushConstantRange pushRange;
|
||||||
|
pushRange.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||||
|
pushRange.offset = 0;
|
||||||
|
pushRange.size = sizeof(DxvkMetaMipGenPushConstants);
|
||||||
|
|
||||||
|
VkPipelineLayoutCreateInfo info;
|
||||||
|
info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
|
||||||
|
info.pNext = nullptr;
|
||||||
|
info.flags = 0;
|
||||||
|
info.setLayoutCount = 1;
|
||||||
|
info.pSetLayouts = &descriptorSetLayout;
|
||||||
|
info.pushConstantRangeCount = 1;
|
||||||
|
info.pPushConstantRanges = &pushRange;
|
||||||
|
|
||||||
|
VkPipelineLayout result = VK_NULL_HANDLE;
|
||||||
|
if (m_vkd->vkCreatePipelineLayout(m_vkd->device(), &info, nullptr, &result) != VK_SUCCESS)
|
||||||
|
throw DxvkError("DxvkMetaMipGenObjects: Failed to create pipeline layout");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
VkPipeline DxvkMetaMipGenObjects::createPipeline(
|
||||||
|
VkImageViewType imageViewType,
|
||||||
|
VkPipelineLayout pipelineLayout,
|
||||||
|
VkRenderPass renderPass) const {
|
||||||
|
std::array<VkPipelineShaderStageCreateInfo, 3> stages;
|
||||||
|
|
||||||
|
VkPipelineShaderStageCreateInfo& vsStage = stages[0];
|
||||||
|
vsStage.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
||||||
|
vsStage.pNext = nullptr;
|
||||||
|
vsStage.flags = 0;
|
||||||
|
vsStage.stage = VK_SHADER_STAGE_VERTEX_BIT;
|
||||||
|
vsStage.module = m_shaderVert;
|
||||||
|
vsStage.pName = "main";
|
||||||
|
vsStage.pSpecializationInfo = nullptr;
|
||||||
|
|
||||||
|
VkPipelineShaderStageCreateInfo& gsStage = stages[1];
|
||||||
|
gsStage.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
||||||
|
gsStage.pNext = nullptr;
|
||||||
|
gsStage.flags = 0;
|
||||||
|
gsStage.stage = VK_SHADER_STAGE_GEOMETRY_BIT;
|
||||||
|
gsStage.module = m_shaderGeom;
|
||||||
|
gsStage.pName = "main";
|
||||||
|
gsStage.pSpecializationInfo = nullptr;
|
||||||
|
|
||||||
|
VkPipelineShaderStageCreateInfo& psStage = stages[2];
|
||||||
|
psStage.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
||||||
|
psStage.pNext = nullptr;
|
||||||
|
psStage.flags = 0;
|
||||||
|
psStage.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||||
|
psStage.module = VK_NULL_HANDLE;
|
||||||
|
psStage.pName = "main";
|
||||||
|
psStage.pSpecializationInfo = nullptr;
|
||||||
|
|
||||||
|
switch (imageViewType) {
|
||||||
|
case VK_IMAGE_VIEW_TYPE_1D_ARRAY: psStage.module = m_shaderFrag1D; break;
|
||||||
|
case VK_IMAGE_VIEW_TYPE_2D_ARRAY: psStage.module = m_shaderFrag2D; break;
|
||||||
|
case VK_IMAGE_VIEW_TYPE_3D: psStage.module = m_shaderFrag3D; break;
|
||||||
|
default: throw DxvkError("DxvkMetaMipGenObjects: Invalid view type");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::array<VkDynamicState, 2> dynStates = {{
|
||||||
|
VK_DYNAMIC_STATE_VIEWPORT,
|
||||||
|
VK_DYNAMIC_STATE_SCISSOR,
|
||||||
|
}};
|
||||||
|
|
||||||
|
VkPipelineDynamicStateCreateInfo dynState;
|
||||||
|
dynState.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
|
||||||
|
dynState.pNext = nullptr;
|
||||||
|
dynState.flags = 0;
|
||||||
|
dynState.dynamicStateCount = dynStates.size();
|
||||||
|
dynState.pDynamicStates = dynStates.data();
|
||||||
|
|
||||||
|
VkPipelineVertexInputStateCreateInfo viState;
|
||||||
|
viState.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
|
||||||
|
viState.pNext = nullptr;
|
||||||
|
viState.flags = 0;
|
||||||
|
viState.vertexBindingDescriptionCount = 0;
|
||||||
|
viState.pVertexBindingDescriptions = nullptr;
|
||||||
|
viState.vertexAttributeDescriptionCount = 0;
|
||||||
|
viState.pVertexAttributeDescriptions = nullptr;
|
||||||
|
|
||||||
|
VkPipelineInputAssemblyStateCreateInfo iaState;
|
||||||
|
iaState.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
|
||||||
|
iaState.pNext = nullptr;
|
||||||
|
iaState.flags = 0;
|
||||||
|
iaState.topology = VK_PRIMITIVE_TOPOLOGY_POINT_LIST;
|
||||||
|
iaState.primitiveRestartEnable = VK_FALSE;
|
||||||
|
|
||||||
|
VkPipelineViewportStateCreateInfo vpState;
|
||||||
|
vpState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
|
||||||
|
vpState.pNext = nullptr;
|
||||||
|
vpState.flags = 0;
|
||||||
|
vpState.viewportCount = 1;
|
||||||
|
vpState.pViewports = nullptr;
|
||||||
|
vpState.scissorCount = 1;
|
||||||
|
vpState.pScissors = nullptr;
|
||||||
|
|
||||||
|
VkPipelineRasterizationStateCreateInfo rsState;
|
||||||
|
rsState.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
|
||||||
|
rsState.pNext = nullptr;
|
||||||
|
rsState.flags = 0;
|
||||||
|
rsState.depthClampEnable = VK_TRUE;
|
||||||
|
rsState.rasterizerDiscardEnable = VK_FALSE;
|
||||||
|
rsState.polygonMode = VK_POLYGON_MODE_FILL;
|
||||||
|
rsState.cullMode = VK_CULL_MODE_NONE;
|
||||||
|
rsState.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
|
||||||
|
rsState.depthBiasEnable = VK_FALSE;
|
||||||
|
rsState.depthBiasConstantFactor = 0.0f;
|
||||||
|
rsState.depthBiasClamp = 0.0f;
|
||||||
|
rsState.depthBiasSlopeFactor = 0.0f;
|
||||||
|
rsState.lineWidth = 1.0f;
|
||||||
|
|
||||||
|
uint32_t msMask = 0xFFFFFFFF;
|
||||||
|
VkPipelineMultisampleStateCreateInfo msState;
|
||||||
|
msState.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
|
||||||
|
msState.pNext = nullptr;
|
||||||
|
msState.flags = 0;
|
||||||
|
msState.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
|
||||||
|
msState.sampleShadingEnable = VK_FALSE;
|
||||||
|
msState.minSampleShading = 1.0f;
|
||||||
|
msState.pSampleMask = &msMask;
|
||||||
|
msState.alphaToCoverageEnable = VK_FALSE;
|
||||||
|
msState.alphaToOneEnable = VK_FALSE;
|
||||||
|
|
||||||
|
VkPipelineColorBlendAttachmentState cbAttachment;
|
||||||
|
cbAttachment.blendEnable = VK_FALSE;
|
||||||
|
cbAttachment.srcColorBlendFactor = VK_BLEND_FACTOR_ONE;
|
||||||
|
cbAttachment.dstColorBlendFactor = VK_BLEND_FACTOR_ZERO;
|
||||||
|
cbAttachment.colorBlendOp = VK_BLEND_OP_ADD;
|
||||||
|
cbAttachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
|
||||||
|
cbAttachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;
|
||||||
|
cbAttachment.alphaBlendOp = VK_BLEND_OP_ADD;
|
||||||
|
cbAttachment.colorWriteMask =
|
||||||
|
VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
|
||||||
|
VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
|
||||||
|
|
||||||
|
VkPipelineColorBlendStateCreateInfo cbState;
|
||||||
|
cbState.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
|
||||||
|
cbState.pNext = nullptr;
|
||||||
|
cbState.flags = 0;
|
||||||
|
cbState.logicOpEnable = VK_FALSE;
|
||||||
|
cbState.logicOp = VK_LOGIC_OP_NO_OP;
|
||||||
|
cbState.attachmentCount = 1;
|
||||||
|
cbState.pAttachments = &cbAttachment;
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < 4; i++)
|
||||||
|
cbState.blendConstants[i] = 0.0f;
|
||||||
|
|
||||||
|
VkGraphicsPipelineCreateInfo info;
|
||||||
|
info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
|
||||||
|
info.pNext = nullptr;
|
||||||
|
info.flags = 0;
|
||||||
|
info.stageCount = stages.size();
|
||||||
|
info.pStages = stages.data();
|
||||||
|
info.pVertexInputState = &viState;
|
||||||
|
info.pInputAssemblyState = &iaState;
|
||||||
|
info.pTessellationState = nullptr;
|
||||||
|
info.pViewportState = &vpState;
|
||||||
|
info.pRasterizationState = &rsState;
|
||||||
|
info.pMultisampleState = &msState;
|
||||||
|
info.pColorBlendState = &cbState;
|
||||||
|
info.pDepthStencilState = nullptr;
|
||||||
|
info.pDynamicState = &dynState;
|
||||||
|
info.layout = pipelineLayout;
|
||||||
|
info.renderPass = renderPass;
|
||||||
|
info.subpass = 0;
|
||||||
|
info.basePipelineHandle = VK_NULL_HANDLE;
|
||||||
|
info.basePipelineIndex = -1;
|
||||||
|
|
||||||
|
VkPipeline result = VK_NULL_HANDLE;
|
||||||
|
if (m_vkd->vkCreateGraphicsPipelines(m_vkd->device(), VK_NULL_HANDLE, 1, &info, nullptr, &result) != VK_SUCCESS)
|
||||||
|
throw DxvkError("DxvkMetaMipGenObjects: Failed to create graphics pipeline");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
232
src/dxvk/dxvk_meta_mipgen.h
Normal file
232
src/dxvk/dxvk_meta_mipgen.h
Normal file
@ -0,0 +1,232 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <mutex>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
#include "../spirv/spirv_code_buffer.h"
|
||||||
|
|
||||||
|
#include "dxvk_hash.h"
|
||||||
|
#include "dxvk_image.h"
|
||||||
|
|
||||||
|
namespace dxvk {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Push constant data
|
||||||
|
*/
|
||||||
|
struct DxvkMetaMipGenPushConstants {
|
||||||
|
uint32_t layerCount;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Mip map generation pipeline key
|
||||||
|
*
|
||||||
|
* We have to create pipelines for each
|
||||||
|
* combination of source image view type
|
||||||
|
* and image format.
|
||||||
|
*/
|
||||||
|
struct DxvkMetaMipGenPipelineKey {
|
||||||
|
VkImageViewType viewType;
|
||||||
|
VkFormat viewFormat;
|
||||||
|
|
||||||
|
bool eq(const DxvkMetaMipGenPipelineKey& other) const {
|
||||||
|
return this->viewType == other.viewType
|
||||||
|
&& this->viewFormat == other.viewFormat;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t hash() const {
|
||||||
|
DxvkHashState result;
|
||||||
|
result.add(uint32_t(this->viewType));
|
||||||
|
result.add(uint32_t(this->viewFormat));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Mip map generation pipeline
|
||||||
|
*
|
||||||
|
* Stores the objects for a single pipeline
|
||||||
|
* that is used for mipmap generation.
|
||||||
|
*/
|
||||||
|
struct DxvkMetaMipGenPipeline {
|
||||||
|
VkDescriptorSetLayout dsetLayout;
|
||||||
|
VkPipelineLayout pipeLayout;
|
||||||
|
VkPipeline pipeHandle;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Mip map generation framebuffer
|
||||||
|
*
|
||||||
|
* Stores the image views and framebuffer
|
||||||
|
* handle used to generate one mip level.
|
||||||
|
*/
|
||||||
|
struct DxvkMetaMipGenPass {
|
||||||
|
VkImageView srcView;
|
||||||
|
VkImageView dstView;
|
||||||
|
VkFramebuffer framebuffer;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Mip map generation render pass
|
||||||
|
*
|
||||||
|
* Stores image views, framebuffer objects and
|
||||||
|
* a render pass object for mip map generation.
|
||||||
|
* This must be created per image view.
|
||||||
|
*/
|
||||||
|
class DxvkMetaMipGenRenderPass : public DxvkResource {
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
DxvkMetaMipGenRenderPass(
|
||||||
|
const Rc<vk::DeviceFn>& vkd,
|
||||||
|
const Rc<DxvkImageView>& view);
|
||||||
|
|
||||||
|
~DxvkMetaMipGenRenderPass();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Render pass handle
|
||||||
|
* \returns Render pass handle
|
||||||
|
*/
|
||||||
|
VkRenderPass renderPass() const {
|
||||||
|
return m_renderPass;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Source image view type
|
||||||
|
*
|
||||||
|
* Use this to figure out which type the
|
||||||
|
* resource descriptor needs to have.
|
||||||
|
* \returns Source image view type
|
||||||
|
*/
|
||||||
|
VkImageViewType viewType() const {
|
||||||
|
return m_srcViewType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Render pass count
|
||||||
|
*
|
||||||
|
* Number of mip levels to generate.
|
||||||
|
* \returns Render pass count
|
||||||
|
*/
|
||||||
|
uint32_t passCount() const {
|
||||||
|
return m_passes.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Framebuffer handles
|
||||||
|
*
|
||||||
|
* Returns image view and framebuffer handles
|
||||||
|
* required to generate a single mip level.
|
||||||
|
* \param [in] pass Render pass index
|
||||||
|
* \returns Object handles for the given pass
|
||||||
|
*/
|
||||||
|
DxvkMetaMipGenPass pass(uint32_t passId) const {
|
||||||
|
return m_passes.at(passId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Framebuffer size for a given pass
|
||||||
|
*
|
||||||
|
* Stores the width, height, and layer count
|
||||||
|
* of the framebuffer for the given pass ID.
|
||||||
|
*/
|
||||||
|
VkExtent3D passExtent(uint32_t passId) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
Rc<vk::DeviceFn> m_vkd;
|
||||||
|
Rc<DxvkImageView> m_view;
|
||||||
|
|
||||||
|
VkRenderPass m_renderPass;
|
||||||
|
|
||||||
|
VkImageViewType m_srcViewType;
|
||||||
|
VkImageViewType m_dstViewType;
|
||||||
|
|
||||||
|
std::vector<DxvkMetaMipGenPass> m_passes;
|
||||||
|
|
||||||
|
VkRenderPass createRenderPass() const;
|
||||||
|
|
||||||
|
DxvkMetaMipGenPass createFramebuffer(uint32_t pass) const;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Mip map generation objects
|
||||||
|
*
|
||||||
|
* Stores render pass objects and pipelines used
|
||||||
|
* to generate mip maps. Due to Vulkan API design
|
||||||
|
* decisions, we have to create one render pass
|
||||||
|
* and pipeline object per image format used.
|
||||||
|
*/
|
||||||
|
class DxvkMetaMipGenObjects : public RcObject {
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
DxvkMetaMipGenObjects(const Rc<vk::DeviceFn>& vkd);
|
||||||
|
~DxvkMetaMipGenObjects();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Creates a mip map generation pipeline
|
||||||
|
*
|
||||||
|
* \param [in] viewType Source image view type
|
||||||
|
* \param [in] viewFormat Image view format
|
||||||
|
* \returns The mip map generation pipeline
|
||||||
|
*/
|
||||||
|
DxvkMetaMipGenPipeline getPipeline(
|
||||||
|
VkImageViewType viewType,
|
||||||
|
VkFormat viewFormat);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
Rc<vk::DeviceFn> m_vkd;
|
||||||
|
|
||||||
|
VkSampler m_sampler;
|
||||||
|
|
||||||
|
VkShaderModule m_shaderVert;
|
||||||
|
VkShaderModule m_shaderGeom;
|
||||||
|
VkShaderModule m_shaderFrag1D;
|
||||||
|
VkShaderModule m_shaderFrag2D;
|
||||||
|
VkShaderModule m_shaderFrag3D;
|
||||||
|
|
||||||
|
std::mutex m_mutex;
|
||||||
|
|
||||||
|
std::unordered_map<
|
||||||
|
VkFormat,
|
||||||
|
VkRenderPass> m_renderPasses;
|
||||||
|
|
||||||
|
std::unordered_map<
|
||||||
|
DxvkMetaMipGenPipelineKey,
|
||||||
|
DxvkMetaMipGenPipeline,
|
||||||
|
DxvkHash, DxvkEq> m_pipelines;
|
||||||
|
|
||||||
|
VkRenderPass getRenderPass(
|
||||||
|
VkFormat viewFormat);
|
||||||
|
|
||||||
|
VkSampler createSampler() const;
|
||||||
|
|
||||||
|
VkShaderModule createShaderModule(
|
||||||
|
const SpirvCodeBuffer& code) const;
|
||||||
|
|
||||||
|
DxvkMetaMipGenPipeline createPipeline(
|
||||||
|
const DxvkMetaMipGenPipelineKey& key);
|
||||||
|
|
||||||
|
VkRenderPass createRenderPass(
|
||||||
|
VkFormat format) const;
|
||||||
|
|
||||||
|
VkDescriptorSetLayout createDescriptorSetLayout(
|
||||||
|
VkImageViewType viewType) const;
|
||||||
|
|
||||||
|
VkPipelineLayout createPipelineLayout(
|
||||||
|
VkDescriptorSetLayout descriptorSetLayout) const;
|
||||||
|
|
||||||
|
VkPipeline createPipeline(
|
||||||
|
VkImageViewType imageViewType,
|
||||||
|
VkPipelineLayout pipelineLayout,
|
||||||
|
VkRenderPass renderPass) const;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
@ -4,9 +4,7 @@
|
|||||||
namespace dxvk {
|
namespace dxvk {
|
||||||
|
|
||||||
DxvkPipelineCompiler::DxvkPipelineCompiler() {
|
DxvkPipelineCompiler::DxvkPipelineCompiler() {
|
||||||
// Use ~half the CPU cores for pipeline compilation
|
constexpr uint32_t threadCount = 1u;
|
||||||
const uint32_t threadCount = std::max<uint32_t>(
|
|
||||||
1u, std::thread::hardware_concurrency() / 2);
|
|
||||||
|
|
||||||
Logger::debug(str::format(
|
Logger::debug(str::format(
|
||||||
"DxvkPipelineCompiler: Using ", threadCount, " workers"));
|
"DxvkPipelineCompiler: Using ", threadCount, " workers"));
|
||||||
|
@ -11,6 +11,22 @@ namespace dxvk {
|
|||||||
|
|
||||||
class DxvkShader;
|
class DxvkShader;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Built-in specialization constants
|
||||||
|
*
|
||||||
|
* These specialization constants allow the SPIR-V
|
||||||
|
* shaders to access some pipeline state like D3D
|
||||||
|
* shaders do. They need to be filled in by the
|
||||||
|
* implementation at pipeline compilation time.
|
||||||
|
*/
|
||||||
|
enum class DxvkSpecConstantId : uint32_t {
|
||||||
|
RasterizerSampleCount = 0x10000,
|
||||||
|
|
||||||
|
SpecConstantIdMin = RasterizerSampleCount,
|
||||||
|
SpecConstantIdMax = RasterizerSampleCount,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Shader interface slots
|
* \brief Shader interface slots
|
||||||
*
|
*
|
||||||
|
41
src/dxvk/dxvk_spec_const.cpp
Normal file
41
src/dxvk/dxvk_spec_const.cpp
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
#include "dxvk_spec_const.h"
|
||||||
|
|
||||||
|
#define SET_CONSTANT_ENTRY(specId, member) \
|
||||||
|
this->setConstantEntry(specId, \
|
||||||
|
offsetof(DxvkSpecConstantData, member), \
|
||||||
|
sizeof(DxvkSpecConstantData::member))
|
||||||
|
|
||||||
|
namespace dxvk {
|
||||||
|
|
||||||
|
DxvkSpecConstantMap g_specConstantMap;
|
||||||
|
|
||||||
|
DxvkSpecConstantMap::DxvkSpecConstantMap() {
|
||||||
|
SET_CONSTANT_ENTRY(DxvkSpecConstantId::RasterizerSampleCount, rasterizerSampleCount);
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < MaxNumActiveBindings; i++)
|
||||||
|
this->setBindingEntry(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void DxvkSpecConstantMap::setConstantEntry(
|
||||||
|
DxvkSpecConstantId specId,
|
||||||
|
uint32_t offset,
|
||||||
|
uint32_t size) {
|
||||||
|
VkSpecializationMapEntry entry;
|
||||||
|
entry.constantID = uint32_t(specId);
|
||||||
|
entry.offset = offset;
|
||||||
|
entry.size = size;
|
||||||
|
m_mapEntries[uint32_t(specId) - uint32_t(DxvkSpecConstantId::SpecConstantIdMin)] = entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void DxvkSpecConstantMap::setBindingEntry(
|
||||||
|
uint32_t binding) {
|
||||||
|
VkSpecializationMapEntry entry;
|
||||||
|
entry.constantID = binding;
|
||||||
|
entry.offset = sizeof(VkBool32) * binding + offsetof(DxvkSpecConstantData, activeBindings);
|
||||||
|
entry.size = sizeof(VkBool32);
|
||||||
|
m_mapEntries[MaxNumSpecConstants + binding] = entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
72
src/dxvk/dxvk_spec_const.h
Normal file
72
src/dxvk/dxvk_spec_const.h
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "dxvk_limits.h"
|
||||||
|
#include "dxvk_shader.h"
|
||||||
|
|
||||||
|
namespace dxvk {
|
||||||
|
|
||||||
|
constexpr uint32_t MaxNumSpecConstants = 1
|
||||||
|
+ uint32_t(DxvkSpecConstantId::SpecConstantIdMax)
|
||||||
|
- uint32_t(DxvkSpecConstantId::SpecConstantIdMin);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Spec costant data
|
||||||
|
*
|
||||||
|
* The values are derived from the pipeline
|
||||||
|
* state vector so that they can be used by
|
||||||
|
* the shaders.
|
||||||
|
*/
|
||||||
|
struct DxvkSpecConstantData {
|
||||||
|
uint32_t rasterizerSampleCount;
|
||||||
|
VkBool32 activeBindings[MaxNumActiveBindings];
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Spec constant map
|
||||||
|
*
|
||||||
|
* Stores the specialization constant map.
|
||||||
|
* This can be passed to Vulkan when compiling
|
||||||
|
* both graphics and compute pipelines.
|
||||||
|
*/
|
||||||
|
class DxvkSpecConstantMap {
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
DxvkSpecConstantMap();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Map entry count
|
||||||
|
*
|
||||||
|
* \param [in] bindingCount Number of active bindings
|
||||||
|
* \returns The number of map entries to read
|
||||||
|
*/
|
||||||
|
uint32_t mapEntryCount() const {
|
||||||
|
return m_mapEntries.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Map entry data
|
||||||
|
* \returns Map entries
|
||||||
|
*/
|
||||||
|
const VkSpecializationMapEntry* mapEntryData() const {
|
||||||
|
return m_mapEntries.data();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
std::array<VkSpecializationMapEntry, MaxNumSpecConstants + MaxNumActiveBindings> m_mapEntries;
|
||||||
|
|
||||||
|
void setConstantEntry(
|
||||||
|
DxvkSpecConstantId specId,
|
||||||
|
uint32_t offset,
|
||||||
|
uint32_t size);
|
||||||
|
|
||||||
|
void setBindingEntry(
|
||||||
|
uint32_t binding);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
extern DxvkSpecConstantMap g_specConstantMap;
|
||||||
|
|
||||||
|
}
|
@ -12,6 +12,12 @@ dxvk_shaders = files([
|
|||||||
'shaders/dxvk_clear_image3d_u.comp',
|
'shaders/dxvk_clear_image3d_u.comp',
|
||||||
'shaders/dxvk_clear_image3d_f.comp',
|
'shaders/dxvk_clear_image3d_f.comp',
|
||||||
|
|
||||||
|
'shaders/dxvk_mipgen_vert.vert',
|
||||||
|
'shaders/dxvk_mipgen_geom.geom',
|
||||||
|
'shaders/dxvk_mipgen_frag_1d.frag',
|
||||||
|
'shaders/dxvk_mipgen_frag_2d.frag',
|
||||||
|
'shaders/dxvk_mipgen_frag_3d.frag',
|
||||||
|
|
||||||
'hud/shaders/hud_line.frag',
|
'hud/shaders/hud_line.frag',
|
||||||
'hud/shaders/hud_text.frag',
|
'hud/shaders/hud_text.frag',
|
||||||
'hud/shaders/hud_vert.vert',
|
'hud/shaders/hud_vert.vert',
|
||||||
@ -41,6 +47,7 @@ dxvk_src = files([
|
|||||||
'dxvk_main.cpp',
|
'dxvk_main.cpp',
|
||||||
'dxvk_memory.cpp',
|
'dxvk_memory.cpp',
|
||||||
'dxvk_meta_clear.cpp',
|
'dxvk_meta_clear.cpp',
|
||||||
|
'dxvk_meta_mipgen.cpp',
|
||||||
'dxvk_meta_resolve.cpp',
|
'dxvk_meta_resolve.cpp',
|
||||||
'dxvk_openvr.cpp',
|
'dxvk_openvr.cpp',
|
||||||
'dxvk_pipecache.cpp',
|
'dxvk_pipecache.cpp',
|
||||||
@ -55,6 +62,7 @@ dxvk_src = files([
|
|||||||
'dxvk_resource.cpp',
|
'dxvk_resource.cpp',
|
||||||
'dxvk_sampler.cpp',
|
'dxvk_sampler.cpp',
|
||||||
'dxvk_shader.cpp',
|
'dxvk_shader.cpp',
|
||||||
|
'dxvk_spec_const.cpp',
|
||||||
'dxvk_staging.cpp',
|
'dxvk_staging.cpp',
|
||||||
'dxvk_stats.cpp',
|
'dxvk_stats.cpp',
|
||||||
'dxvk_surface.cpp',
|
'dxvk_surface.cpp',
|
||||||
|
11
src/dxvk/shaders/dxvk_mipgen_frag_1d.frag
Normal file
11
src/dxvk/shaders/dxvk_mipgen_frag_1d.frag
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#version 450
|
||||||
|
|
||||||
|
layout(set = 0, binding = 0)
|
||||||
|
uniform sampler1DArray s_texture;
|
||||||
|
|
||||||
|
layout(location = 0) in vec3 i_pos;
|
||||||
|
layout(location = 0) out vec4 o_color;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
o_color = texture(s_texture, i_pos.xz);
|
||||||
|
}
|
11
src/dxvk/shaders/dxvk_mipgen_frag_2d.frag
Normal file
11
src/dxvk/shaders/dxvk_mipgen_frag_2d.frag
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#version 450
|
||||||
|
|
||||||
|
layout(set = 0, binding = 0)
|
||||||
|
uniform sampler2DArray s_texture;
|
||||||
|
|
||||||
|
layout(location = 0) in vec3 i_pos;
|
||||||
|
layout(location = 0) out vec4 o_color;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
o_color = texture(s_texture, i_pos);
|
||||||
|
}
|
17
src/dxvk/shaders/dxvk_mipgen_frag_3d.frag
Normal file
17
src/dxvk/shaders/dxvk_mipgen_frag_3d.frag
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
#version 450
|
||||||
|
|
||||||
|
layout(set = 0, binding = 0)
|
||||||
|
uniform sampler3D s_texture;
|
||||||
|
|
||||||
|
layout(location = 0) in vec3 i_pos;
|
||||||
|
layout(location = 0) out vec4 o_color;
|
||||||
|
|
||||||
|
layout(push_constant)
|
||||||
|
uniform push_block {
|
||||||
|
uint p_layer_count;
|
||||||
|
};
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
o_color = texture(s_texture, vec3(i_pos.xy,
|
||||||
|
(i_pos.z + 0.5f) / float(p_layer_count)));
|
||||||
|
}
|
25
src/dxvk/shaders/dxvk_mipgen_geom.geom
Normal file
25
src/dxvk/shaders/dxvk_mipgen_geom.geom
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
#version 450
|
||||||
|
|
||||||
|
layout(points) in;
|
||||||
|
layout(triangle_strip, max_vertices = 4) out;
|
||||||
|
|
||||||
|
layout(location = 0) in int i_instance[1];
|
||||||
|
layout(location = 0) out vec3 o_pos;
|
||||||
|
|
||||||
|
const vec4 g_vpos[4] = {
|
||||||
|
vec4(-1.0f, -1.0f, 0.0f, 1.0f),
|
||||||
|
vec4(-1.0f, 1.0f, 0.0f, 1.0f),
|
||||||
|
vec4( 1.0f, -1.0f, 0.0f, 1.0f),
|
||||||
|
vec4( 1.0f, 1.0f, 0.0f, 1.0f),
|
||||||
|
};
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
o_pos = vec3(0.5f + 0.5f * g_vpos[i].xy, float(i_instance[0]));
|
||||||
|
gl_Position = g_vpos[i];
|
||||||
|
gl_Layer = i_instance[0];
|
||||||
|
EmitVertex();
|
||||||
|
}
|
||||||
|
|
||||||
|
EndPrimitive();
|
||||||
|
}
|
8
src/dxvk/shaders/dxvk_mipgen_vert.vert
Normal file
8
src/dxvk/shaders/dxvk_mipgen_vert.vert
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
#version 450
|
||||||
|
|
||||||
|
layout(location = 0) out int o_instance;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
o_instance = gl_InstanceIndex;
|
||||||
|
gl_Position = vec4(0.0f, 0.0f, 0.0f, 1.0f);
|
||||||
|
}
|
@ -92,6 +92,16 @@ namespace dxvk {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void SpirvModule::setInvocations(
|
||||||
|
uint32_t entryPointId,
|
||||||
|
uint32_t invocations) {
|
||||||
|
m_execModeInfo.putIns (spv::OpExecutionMode, 4);
|
||||||
|
m_execModeInfo.putWord (entryPointId);
|
||||||
|
m_execModeInfo.putWord (spv::ExecutionModeInvocations);
|
||||||
|
m_execModeInfo.putInt32(invocations);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void SpirvModule::setLocalSize(
|
void SpirvModule::setLocalSize(
|
||||||
uint32_t entryPointId,
|
uint32_t entryPointId,
|
||||||
uint32_t x,
|
uint32_t x,
|
||||||
@ -330,6 +340,19 @@ namespace dxvk {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint32_t SpirvModule::specConst32(
|
||||||
|
uint32_t typeId,
|
||||||
|
uint32_t value) {
|
||||||
|
uint32_t resultId = this->allocateId();
|
||||||
|
|
||||||
|
m_typeConstDefs.putIns (spv::OpSpecConstant, 4);
|
||||||
|
m_typeConstDefs.putWord (typeId);
|
||||||
|
m_typeConstDefs.putWord (resultId);
|
||||||
|
m_typeConstDefs.putWord (value);
|
||||||
|
return resultId;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void SpirvModule::decorate(
|
void SpirvModule::decorate(
|
||||||
uint32_t object,
|
uint32_t object,
|
||||||
spv::Decoration decoration) {
|
spv::Decoration decoration) {
|
||||||
|
@ -79,6 +79,10 @@ namespace dxvk {
|
|||||||
uint32_t entryPointId,
|
uint32_t entryPointId,
|
||||||
spv::ExecutionMode executionMode);
|
spv::ExecutionMode executionMode);
|
||||||
|
|
||||||
|
void setInvocations(
|
||||||
|
uint32_t entryPointId,
|
||||||
|
uint32_t invocations);
|
||||||
|
|
||||||
void setLocalSize(
|
void setLocalSize(
|
||||||
uint32_t entryPointId,
|
uint32_t entryPointId,
|
||||||
uint32_t x,
|
uint32_t x,
|
||||||
@ -154,6 +158,10 @@ namespace dxvk {
|
|||||||
uint32_t specConstBool(
|
uint32_t specConstBool(
|
||||||
bool v);
|
bool v);
|
||||||
|
|
||||||
|
uint32_t specConst32(
|
||||||
|
uint32_t typeId,
|
||||||
|
uint32_t value);
|
||||||
|
|
||||||
void decorate(
|
void decorate(
|
||||||
uint32_t object,
|
uint32_t object,
|
||||||
spv::Decoration decoration);
|
spv::Decoration decoration);
|
||||||
|
@ -1,6 +1,10 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef _MSC_VER
|
||||||
#include <x86intrin.h>
|
#include <x86intrin.h>
|
||||||
|
#else
|
||||||
|
#include <intrin.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace dxvk::bit {
|
namespace dxvk::bit {
|
||||||
|
|
||||||
@ -17,7 +21,9 @@ namespace dxvk::bit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline uint32_t tzcnt(uint32_t n) {
|
inline uint32_t tzcnt(uint32_t n) {
|
||||||
#if defined(__BMI__)
|
#if defined(_MSC_VER)
|
||||||
|
return _tzcnt_u32(n);
|
||||||
|
#elif defined(__BMI__)
|
||||||
return __tzcnt_u32(n);
|
return __tzcnt_u32(n);
|
||||||
#elif defined(__GNUC__)
|
#elif defined(__GNUC__)
|
||||||
uint32_t res;
|
uint32_t res;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user