1
0
mirror of https://github.com/doitsujin/dxvk.git synced 2025-03-14 22:29:15 +01:00

[dxvk,d3d11,d3d9] Refactor viewport updates

Might as well use the CS chunk array functionality for this.
This commit is contained in:
Philip Rebohle 2025-03-11 00:42:28 +01:00
parent fed3b7cce4
commit f37df19da2
6 changed files with 68 additions and 116 deletions

View File

@ -2469,8 +2469,8 @@ namespace dxvk {
// In D3D11, the rasterizer state defines whether the scissor test is // In D3D11, the rasterizer state defines whether the scissor test is
// enabled, so if that changes, we need to update scissor rects as well. // enabled, so if that changes, we need to update scissor rects as well.
bool currScissorEnable = currRasterizerState != nullptr ? currRasterizerState->Desc()->ScissorEnable : false; bool currScissorEnable = currRasterizerState && currRasterizerState->Desc()->ScissorEnable;
bool nextScissorEnable = nextRasterizerState != nullptr ? nextRasterizerState->Desc()->ScissorEnable : false; bool nextScissorEnable = nextRasterizerState && nextRasterizerState->Desc()->ScissorEnable;
if (currScissorEnable != nextScissorEnable) if (currScissorEnable != nextScissorEnable)
ApplyViewportState(); ApplyViewportState();
@ -2545,13 +2545,8 @@ namespace dxvk {
} }
} }
if (m_state.rs.state != nullptr && dirty) { if (dirty && m_state.rs.state && m_state.rs.state->Desc()->ScissorEnable)
D3D11_RASTERIZER_DESC rsDesc; ApplyViewportState();
m_state.rs.state->GetDesc(&rsDesc);
if (rsDesc.ScissorEnable)
ApplyViewportState();
}
} }
@ -3487,92 +3482,52 @@ namespace dxvk {
template<typename ContextType> template<typename ContextType>
void D3D11CommonContext<ContextType>::ApplyViewportState() { void D3D11CommonContext<ContextType>::ApplyViewportState() {
std::array<VkViewport, D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE> viewports;
std::array<VkRect2D, D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE> scissors;
// The backend can't handle a viewport count of zero,
// so we should at least specify one empty viewport
uint32_t viewportCount = m_state.rs.numViewports; uint32_t viewportCount = m_state.rs.numViewports;
if (unlikely(!viewportCount)) { if (likely(viewportCount)) {
viewportCount = 1; EmitCsCmd<DxvkViewport>(D3D11CmdType::None, viewportCount,
viewports[0] = VkViewport(); [] (DxvkContext* ctx, const DxvkViewport* viewports, size_t count) {
scissors [0] = VkRect2D(); ctx->setViewports(count, viewports);
} });
// D3D11's coordinate system has its origin in the bottom left, // Vulkan does not provide an easy way to disable the scissor test,
// but the viewport coordinates are aligned to the top-left // Set scissor rects that are at least as large as the framebuffer.
// corner so we can get away with flipping the viewport. bool enableScissorTest = m_state.rs.state && m_state.rs.state->Desc()->ScissorEnable;
for (uint32_t i = 0; i < m_state.rs.numViewports; i++) {
const D3D11_VIEWPORT& vp = m_state.rs.viewports[i];
viewports[i] = VkViewport { // D3D11's coordinate system has its origin in the bottom left,
vp.TopLeftX, vp.Height + vp.TopLeftY, // but the viewport coordinates are aligned to the top-left
vp.Width, -vp.Height, // corner so we can get away with flipping the viewport.
vp.MinDepth, vp.MaxDepth, for (uint32_t i = 0; i < viewportCount; i++) {
}; const auto& vp = m_state.rs.viewports[i];
}
// Scissor rectangles. Vulkan does not provide an easy way auto* dst = new (m_csData->at(i)) DxvkViewport();
// to disable the scissor test, so we'll have to set scissor dst->viewport.x = vp.TopLeftX;
// rects that are at least as large as the framebuffer. dst->viewport.y = vp.Height + vp.TopLeftY;
bool enableScissorTest = false; dst->viewport.width = vp.Width;
dst->viewport.height = -vp.Height;
if (m_state.rs.state != nullptr) { dst->viewport.minDepth = vp.MinDepth;
D3D11_RASTERIZER_DESC rsDesc; dst->viewport.maxDepth = vp.MaxDepth;
m_state.rs.state->GetDesc(&rsDesc);
enableScissorTest = rsDesc.ScissorEnable;
}
for (uint32_t i = 0; i < m_state.rs.numViewports; i++) { if (!enableScissorTest) {
if (!enableScissorTest) { dst->scissor.offset = VkOffset2D { 0, 0 };
scissors[i] = VkRect2D { dst->scissor.extent = VkExtent2D {
VkOffset2D { 0, 0 },
VkExtent2D {
D3D11_VIEWPORT_BOUNDS_MAX, D3D11_VIEWPORT_BOUNDS_MAX,
D3D11_VIEWPORT_BOUNDS_MAX } }; D3D11_VIEWPORT_BOUNDS_MAX };
} else if (i >= m_state.rs.numScissors) { } else if (i < m_state.rs.numScissors) {
scissors[i] = VkRect2D { const auto& sr = m_state.rs.scissors[i];
VkOffset2D { 0, 0 },
VkExtent2D { 0, 0 } };
} else {
D3D11_RECT sr = m_state.rs.scissors[i];
VkOffset2D srPosA; dst->scissor.offset = VkOffset2D { sr.left, sr.top };
srPosA.x = std::max<int32_t>(0, sr.left); dst->scissor.extent = VkExtent2D {
srPosA.y = std::max<int32_t>(0, sr.top); uint32_t(std::max(sr.left, sr.right) - sr.left),
uint32_t(std::max(sr.top, 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[i] = VkRect2D { srPosA, srSize };
} }
}
if (likely(viewportCount == 1)) {
EmitCs([
cViewport = viewports[0],
cScissor = scissors[0]
] (DxvkContext* ctx) {
ctx->setViewports(1,
&cViewport,
&cScissor);
});
} else { } else {
EmitCs([ // The backend can't handle a viewport count of zero,
cViewportCount = viewportCount, // so we should at least specify one empty viewport
cViewports = viewports, EmitCs([] (DxvkContext* ctx) {
cScissors = scissors DxvkViewport viewport = { };
] (DxvkContext* ctx) { ctx->setViewports(1, &viewport);
ctx->setViewports(
cViewportCount,
cViewports.data(),
cScissors.data());
}); });
} }
} }
@ -4802,10 +4757,8 @@ namespace dxvk {
ctx->setStencilReference(D3D11_DEFAULT_STENCIL_REFERENCE); ctx->setStencilReference(D3D11_DEFAULT_STENCIL_REFERENCE);
// Reset viewports // Reset viewports
auto viewport = VkViewport(); DxvkViewport viewport = { };
auto scissor = VkRect2D(); ctx->setViewports(1, &viewport);
ctx->setViewports(1, &viewport, &scissor);
// Unbind indirect draw buffer // Unbind indirect draw buffer
ctx->bindDrawBuffers(DxvkBufferSlice(), DxvkBufferSlice()); ctx->bindDrawBuffers(DxvkBufferSlice(), DxvkBufferSlice());

View File

@ -1293,8 +1293,10 @@ namespace dxvk {
Rc<DxvkResourceAllocation> uboSlice = m_ubo->allocateStorage(); Rc<DxvkResourceAllocation> uboSlice = m_ubo->allocateStorage();
memcpy(uboSlice->mapPtr(), &uboData, sizeof(uboData)); memcpy(uboSlice->mapPtr(), &uboData, sizeof(uboData));
DxvkViewport vp = { viewport, scissor };
ctx->invalidateBuffer(m_ubo, std::move(uboSlice)); ctx->invalidateBuffer(m_ubo, std::move(uboSlice));
ctx->setViewports(1, &viewport, &scissor); ctx->setViewports(1, &vp);
ctx->bindShader<VK_SHADER_STAGE_VERTEX_BIT>(Rc<DxvkShader>(m_vs)); ctx->bindShader<VK_SHADER_STAGE_VERTEX_BIT>(Rc<DxvkShader>(m_vs));
ctx->bindShader<VK_SHADER_STAGE_FRAGMENT_BIT>(Rc<DxvkShader>(m_fs)); ctx->bindShader<VK_SHADER_STAGE_FRAGMENT_BIT>(Rc<DxvkShader>(m_fs));

View File

@ -6732,9 +6732,6 @@ namespace dxvk {
void D3D9DeviceEx::BindViewportAndScissor() { void D3D9DeviceEx::BindViewportAndScissor() {
m_flags.clr(D3D9DeviceFlag::DirtyViewportScissor); m_flags.clr(D3D9DeviceFlag::DirtyViewportScissor);
VkViewport viewport;
VkRect2D scissor;
// D3D9's coordinate system has its origin in the bottom left, // D3D9's coordinate system has its origin in the bottom left,
// but the viewport coordinates are aligned to the top-left // but the viewport coordinates are aligned to the top-left
// corner so we can get away with flipping the viewport. // corner so we can get away with flipping the viewport.
@ -6753,7 +6750,8 @@ namespace dxvk {
zBias = 0.001f; zBias = 0.001f;
} }
viewport = VkViewport{ DxvkViewport state = { };
state.viewport = VkViewport{
float(vp.X) + cf, float(vp.Height + vp.Y) + cf, float(vp.X) + cf, float(vp.Height + vp.Y) + cf,
float(vp.Width), -float(vp.Height), float(vp.Width), -float(vp.Height),
std::clamp(vp.MinZ, 0.0f, 1.0f), std::clamp(vp.MinZ, 0.0f, 1.0f),
@ -6784,22 +6782,18 @@ namespace dxvk {
srSize.width = uint32_t(srPosB.x - srPosA.x); srSize.width = uint32_t(srPosB.x - srPosA.x);
srSize.height = uint32_t(srPosB.y - srPosA.y); srSize.height = uint32_t(srPosB.y - srPosA.y);
scissor = VkRect2D{ srPosA, srSize }; state.scissor = VkRect2D{ srPosA, srSize };
} }
else { else {
scissor = VkRect2D{ state.scissor = VkRect2D{
VkOffset2D { int32_t(vp.X), int32_t(vp.Y) }, VkOffset2D { int32_t(vp.X), int32_t(vp.Y) },
VkExtent2D { vp.Width, vp.Height }}; VkExtent2D { vp.Width, vp.Height }};
} }
EmitCs([ EmitCs([
cViewport = viewport, cViewport = state
cScissor = scissor
] (DxvkContext* ctx) { ] (DxvkContext* ctx) {
ctx->setViewports( ctx->setViewports(1, &cViewport);
1,
&cViewport,
&cScissor);
}); });
} }

View File

@ -2579,16 +2579,15 @@ namespace dxvk {
void DxvkContext::setViewports( void DxvkContext::setViewports(
uint32_t viewportCount, uint32_t viewportCount,
const VkViewport* viewports, const DxvkViewport* viewports) {
const VkRect2D* scissorRects) {
for (uint32_t i = 0; i < viewportCount; i++) { for (uint32_t i = 0; i < viewportCount; i++) {
m_state.vp.viewports[i] = viewports[i]; m_state.vp.viewports[i] = viewports[i].viewport;
m_state.vp.scissorRects[i] = scissorRects[i]; m_state.vp.scissorRects[i] = viewports[i].scissor;
// Vulkan viewports are not allowed to have a width or // Vulkan viewports are not allowed to have a width or
// height of zero, so we fall back to a dummy viewport // height of zero, so we fall back to a dummy viewport
// and instead set an empty scissor rect, which is legal. // and instead set an empty scissor rect, which is legal.
if (viewports[i].width == 0.0f || viewports[i].height == 0.0f) { if (viewports[i].viewport.width <= 0.0f || viewports[i].viewport.height == 0.0f) {
m_state.vp.viewports[i] = VkViewport { m_state.vp.viewports[i] = VkViewport {
0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f }; 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f };
m_state.vp.scissorRects[i] = VkRect2D { m_state.vp.scissorRects[i] = VkRect2D {
@ -2596,7 +2595,7 @@ namespace dxvk {
VkExtent2D { 0, 0 } }; VkExtent2D { 0, 0 } };
} }
} }
m_state.vp.viewportCount = viewportCount; m_state.vp.viewportCount = viewportCount;
m_flags.set(DxvkContextFlag::GpDirtyViewport); m_flags.set(DxvkContextFlag::GpDirtyViewport);
} }

View File

@ -1124,14 +1124,12 @@ namespace dxvk {
* \brief Sets viewports * \brief Sets viewports
* *
* \param [in] viewportCount Number of viewports * \param [in] viewportCount Number of viewports
* \param [in] viewports The viewports * \param [in] viewports The viewports and scissors
* \param [in] scissorRects Schissor rectangles
*/ */
void setViewports( void setViewports(
uint32_t viewportCount, uint32_t viewportCount,
const VkViewport* viewports, const DxvkViewport* viewports);
const VkRect2D* scissorRects);
/** /**
* \brief Sets blend constants * \brief Sets blend constants
* *

View File

@ -114,8 +114,14 @@ namespace dxvk {
std::array<uint32_t, DxvkLimits::MaxNumVertexBindings> vertexStrides = { }; std::array<uint32_t, DxvkLimits::MaxNumVertexBindings> vertexStrides = { };
std::array<uint32_t, DxvkLimits::MaxNumVertexBindings> vertexExtents = { }; std::array<uint32_t, DxvkLimits::MaxNumVertexBindings> vertexExtents = { };
}; };
struct DxvkViewport {
VkViewport viewport = { };
VkRect2D scissor = { };
};
struct DxvkViewportState { struct DxvkViewportState {
uint32_t viewportCount = 0; uint32_t viewportCount = 0;
std::array<VkViewport, DxvkLimits::MaxNumViewports> viewports = { }; std::array<VkViewport, DxvkLimits::MaxNumViewports> viewports = { };