QRhi: Allow negative viewport origin

Do not bound viewport rect to surface size, only scirror rect.
Modifying the viewport will move the view origin changing the
way the scene gets rendered.

Pick-to: 6.4
Task-number: QTBUG-106082
Change-Id: I105516bd460af87727d0e73f580b8cf6b748d87f
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Laszlo Agocs <laszlo.agocs@qt.io>
bb10
Antti Määttä 2022-10-19 09:04:54 +03:00
parent d4b0e0d02e
commit d46ad52872
4 changed files with 30 additions and 19 deletions

View File

@ -245,7 +245,13 @@ private:
friend class QRhiResourceUpdateBatchPrivate;
};
template<typename T, size_t N>
enum QRhiTargetRectBoundMode
{
UnBounded,
Bounded
};
template<QRhiTargetRectBoundMode boundingMode, typename T, size_t N>
bool qrhi_toTopLeftRenderTargetRect(const QSize &outputSize, const std::array<T, N> &r,
T *x, T *y, T *w, T *h)
{
@ -256,7 +262,7 @@ bool qrhi_toTopLeftRenderTargetRect(const QSize &outputSize, const std::array<T,
// or height. We must handle all other input gracefully, clamping to a zero
// width or height rect in the worst case, and ensuring the resulting rect
// is inside the rendertarget's bounds because some APIs' validation/debug
// layers are allergic to out of bounds scissor or viewport rects.
// layers are allergic to out of bounds scissor rects.
const T outputWidth = outputSize.width();
const T outputHeight = outputSize.height();
@ -268,20 +274,23 @@ bool qrhi_toTopLeftRenderTargetRect(const QSize &outputSize, const std::array<T,
*x = r[0];
*y = outputHeight - (r[1] + inputHeight);
*w = inputWidth;
*h = inputHeight;
const T widthOffset = *x < 0 ? -*x : 0;
const T heightOffset = *y < 0 ? -*y : 0;
*w = *x < outputWidth ? qMax<T>(0, inputWidth - widthOffset) : 0;
*h = *y < outputHeight ? qMax<T>(0, inputHeight - heightOffset) : 0;
if (boundingMode == Bounded) {
const T widthOffset = *x < 0 ? -*x : 0;
const T heightOffset = *y < 0 ? -*y : 0;
*w = *x < outputWidth ? qMax<T>(0, inputWidth - widthOffset) : 0;
*h = *y < outputHeight ? qMax<T>(0, inputHeight - heightOffset) : 0;
*x = qBound<T>(0, *x, outputWidth - 1);
*y = qBound<T>(0, *y, outputHeight - 1);
if (*x + *w > outputWidth)
*w = qMax<T>(0, outputWidth - *x);
if (*y + *h > outputHeight)
*h = qMax<T>(0, outputHeight - *y);
*x = qBound<T>(0, *x, outputWidth - 1);
*y = qBound<T>(0, *y, outputHeight - 1);
if (*x + *w > outputWidth)
*w = qMax<T>(0, outputWidth - *x);
if (*y + *h > outputHeight)
*h = qMax<T>(0, outputHeight - *y);
}
return true;
}

View File

@ -1084,7 +1084,7 @@ void QRhiD3D11::setViewport(QRhiCommandBuffer *cb, const QRhiViewport &viewport)
// d3d expects top-left, QRhiViewport is bottom-left
float x, y, w, h;
if (!qrhi_toTopLeftRenderTargetRect(outputSize, viewport.viewport(), &x, &y, &w, &h))
if (!qrhi_toTopLeftRenderTargetRect<UnBounded>(outputSize, viewport.viewport(), &x, &y, &w, &h))
return;
QD3D11CommandBuffer::Command &cmd(cbD->commands.get());
@ -1106,7 +1106,7 @@ void QRhiD3D11::setScissor(QRhiCommandBuffer *cb, const QRhiScissor &scissor)
// d3d expects top-left, QRhiScissor is bottom-left
int x, y, w, h;
if (!qrhi_toTopLeftRenderTargetRect(outputSize, scissor.scissor(), &x, &y, &w, &h))
if (!qrhi_toTopLeftRenderTargetRect<Bounded>(outputSize, scissor.scissor(), &x, &y, &w, &h))
return;
QD3D11CommandBuffer::Command &cmd(cbD->commands.get());

View File

@ -1643,7 +1643,7 @@ void QRhiMetal::setViewport(QRhiCommandBuffer *cb, const QRhiViewport &viewport)
// x,y is top-left in MTLViewportRect but bottom-left in QRhiViewport
float x, y, w, h;
if (!qrhi_toTopLeftRenderTargetRect(outputSize, viewport.viewport(), &x, &y, &w, &h))
if (!qrhi_toTopLeftRenderTargetRect<UnBounded>(outputSize, viewport.viewport(), &x, &y, &w, &h))
return;
MTLViewport vp;
@ -1659,6 +1659,7 @@ void QRhiMetal::setViewport(QRhiCommandBuffer *cb, const QRhiViewport &viewport)
if (cbD->currentGraphicsPipeline
&& !cbD->currentGraphicsPipeline->m_flags.testFlag(QRhiGraphicsPipeline::UsesScissor)) {
MTLScissorRect s;
qrhi_toTopLeftRenderTargetRect<Bounded>(outputSize, viewport.viewport(), &x, &y, &w, &h);
s.x = NSUInteger(x);
s.y = NSUInteger(y);
s.width = NSUInteger(w);
@ -1676,7 +1677,7 @@ void QRhiMetal::setScissor(QRhiCommandBuffer *cb, const QRhiScissor &scissor)
// x,y is top-left in MTLScissorRect but bottom-left in QRhiScissor
int x, y, w, h;
if (!qrhi_toTopLeftRenderTargetRect(outputSize, scissor.scissor(), &x, &y, &w, &h))
if (!qrhi_toTopLeftRenderTargetRect<Bounded>(outputSize, scissor.scissor(), &x, &y, &w, &h))
return;
MTLScissorRect s;

View File

@ -4927,7 +4927,7 @@ void QRhiVulkan::setViewport(QRhiCommandBuffer *cb, const QRhiViewport &viewport
// x,y is top-left in VkViewport but bottom-left in QRhiViewport
float x, y, w, h;
if (!qrhi_toTopLeftRenderTargetRect(outputSize, viewport.viewport(), &x, &y, &w, &h))
if (!qrhi_toTopLeftRenderTargetRect<UnBounded>(outputSize, viewport.viewport(), &x, &y, &w, &h))
return;
QVkCommandBuffer::Command &cmd(cbD->commands.get());
@ -4951,6 +4951,7 @@ void QRhiVulkan::setViewport(QRhiCommandBuffer *cb, const QRhiViewport &viewport
->m_flags.testFlag(QRhiGraphicsPipeline::UsesScissor)) {
QVkCommandBuffer::Command &cmd(cbD->commands.get());
VkRect2D *s = &cmd.args.setScissor.scissor;
qrhi_toTopLeftRenderTargetRect<Bounded>(outputSize, viewport.viewport(), &x, &y, &w, &h);
s->offset.x = int32_t(x);
s->offset.y = int32_t(y);
s->extent.width = uint32_t(w);
@ -4973,7 +4974,7 @@ void QRhiVulkan::setScissor(QRhiCommandBuffer *cb, const QRhiScissor &scissor)
// x,y is top-left in VkRect2D but bottom-left in QRhiScissor
int x, y, w, h;
if (!qrhi_toTopLeftRenderTargetRect(outputSize, scissor.scissor(), &x, &y, &w, &h))
if (!qrhi_toTopLeftRenderTargetRect<Bounded>(outputSize, scissor.scissor(), &x, &y, &w, &h))
return;
QVkCommandBuffer::Command &cmd(cbD->commands.get());