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

View File

@ -1293,8 +1293,10 @@ namespace dxvk {
Rc<DxvkResourceAllocation> uboSlice = m_ubo->allocateStorage();
memcpy(uboSlice->mapPtr(), &uboData, sizeof(uboData));
DxvkViewport vp = { viewport, scissor };
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_FRAGMENT_BIT>(Rc<DxvkShader>(m_fs));

View File

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

View File

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

View File

@ -1124,14 +1124,12 @@ namespace dxvk {
* \brief Sets viewports
*
* \param [in] viewportCount Number of viewports
* \param [in] viewports The viewports
* \param [in] scissorRects Schissor rectangles
* \param [in] viewports The viewports and scissors
*/
void setViewports(
uint32_t viewportCount,
const VkViewport* viewports,
const VkRect2D* scissorRects);
const DxvkViewport* viewports);
/**
* \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> vertexExtents = { };
};
struct DxvkViewport {
VkViewport viewport = { };
VkRect2D scissor = { };
};
struct DxvkViewportState {
uint32_t viewportCount = 0;
std::array<VkViewport, DxvkLimits::MaxNumViewports> viewports = { };