Skip to content

Commit 9237670

Browse files
Fixed viewport issue when renderning with multiple render targets. (#1218)
- Refactored the Framebuffer class to make it work with multiple render targets and viewports. - Added extra test for multiple render targets.
1 parent fa9c432 commit 9237670

File tree

4 files changed

+56
-83
lines changed

4 files changed

+56
-83
lines changed
22 KB
Loading

Apps/ValidationTests/Scripts/config.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545
{
4646
"title": "Glow layer and LODs",
4747
"playgroundId": "#UNS6ZV#2",
48-
"renderCount": 5,
48+
"renderCount": 50,
4949
"referenceImage": "glowlayerandlods.png"
5050
},
5151
{
@@ -200,6 +200,12 @@
200200
"playgroundId": "#1LK70I#22",
201201
"referenceImage": "multiCameraRendering.png"
202202
},
203+
{
204+
"title": "Multi cameras and output render target",
205+
"renderCount": 2,
206+
"playgroundId": "#BCYE7J#31",
207+
"referenceImage": "multiCamerasOutputRenderTarget.png"
208+
},
203209
{
204210
"title": "setParent",
205211
"playgroundId": "#JD49CT#2",

Core/Graphics/InternalInclude/Babylon/Graphics/FrameBuffer.h

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -54,15 +54,13 @@ namespace Babylon::Graphics
5454
const bool m_hasDepth;
5555
const bool m_hasStencil;
5656

57-
bgfx::ViewId m_viewId{};
58-
ViewPort m_viewPort{};
59-
uint16_t m_flags{BGFX_CLEAR_NONE};
60-
uint32_t m_rgba{0x000000ff};
61-
float m_depth{1.0f};
62-
uint8_t m_stencil{0};
57+
std::optional<bgfx::ViewId> m_viewId;
6358

64-
bool m_hasViewIdBeenUsed{false};
59+
ViewPort m_bgfxViewPort;
60+
ViewPort m_desiredViewPort;
6561

6662
bool m_disposed{false};
63+
64+
void SetBgfxViewPort(bgfx::Encoder& encoder, const ViewPort& viewPort);
6765
};
6866
}

Core/Graphics/Source/FrameBuffer.cpp

Lines changed: 44 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -5,33 +5,15 @@
55

66
namespace Babylon::Graphics
77
{
8-
namespace
9-
{
10-
void SetDefaultClearMode(bgfx::ViewId viewId, bgfx::FrameBufferHandle handle, uint16_t flags, uint32_t rgba, float depth, uint8_t stencil)
11-
{
12-
bgfx::setViewMode(viewId, bgfx::ViewMode::Sequential);
13-
bgfx::setViewClear(viewId, flags, rgba, depth, stencil);
14-
bgfx::setViewFrameBuffer(viewId, handle);
15-
}
16-
17-
void setViewPort(bgfx::ViewId viewId, const ViewPort& viewPort, uint16_t width, uint16_t height)
18-
{
19-
bgfx::setViewRect(viewId,
20-
static_cast<uint16_t>(viewPort.X * width),
21-
static_cast<uint16_t>(viewPort.Y * height),
22-
static_cast<uint16_t>(viewPort.Width * width),
23-
static_cast<uint16_t>(viewPort.Height * height));
24-
}
25-
}
26-
278
FrameBuffer::FrameBuffer(DeviceContext& context, bgfx::FrameBufferHandle handle, uint16_t width, uint16_t height, bool defaultBackBuffer, bool hasDepth, bool hasStencil)
289
: m_context{context}
2910
, m_handle{handle}
3011
, m_width{width}
3112
, m_height{height}
3213
, m_defaultBackBuffer{defaultBackBuffer}
33-
, m_hasDepth(hasDepth)
34-
, m_hasStencil(hasStencil)
14+
, m_hasDepth{hasDepth}
15+
, m_hasStencil{hasStencil}
16+
, m_disposed{false}
3517
{
3618
}
3719

@@ -60,20 +42,9 @@ namespace Babylon::Graphics
6042
return m_defaultBackBuffer;
6143
}
6244

63-
void FrameBuffer::Bind(bgfx::Encoder& encoder)
45+
void FrameBuffer::Bind(bgfx::Encoder&)
6446
{
65-
m_viewId = m_context.AcquireNewViewId(encoder);
66-
67-
//Reset view state for next frame.
68-
m_viewPort = {0, 0, 1, 1};
69-
m_flags = BGFX_CLEAR_NONE;
70-
m_rgba = 0x000000ff;
71-
m_depth = 1.0f;
72-
m_stencil = 0;
73-
74-
SetDefaultClearMode(m_viewId, m_handle, BGFX_CLEAR_NONE, 0x000000ff, 1.0f, 0);
75-
setViewPort(m_viewId, m_viewPort, Width(), Height());
76-
m_hasViewIdBeenUsed = false;
47+
m_viewId.reset();
7748
}
7849

7950
void FrameBuffer::Unbind(bgfx::Encoder&)
@@ -82,61 +53,38 @@ namespace Babylon::Graphics
8253

8354
void FrameBuffer::Clear(bgfx::Encoder& encoder, uint16_t flags, uint32_t rgba, float depth, uint8_t stencil)
8455
{
85-
m_flags = flags;
86-
m_rgba = rgba;
87-
m_depth = depth;
88-
m_stencil = stencil;
56+
// BGFX requires us to create a new viewID, this will ensure that the view gets cleaned.
57+
m_viewId = m_context.AcquireNewViewId(encoder);
8958

90-
if (m_hasViewIdBeenUsed)
91-
{
92-
m_viewId = m_context.AcquireNewViewId(encoder);
93-
SetDefaultClearMode(m_viewId, m_handle, m_flags, m_rgba, m_depth, m_stencil);
94-
setViewPort(m_viewId, m_viewPort, Width(), Height());
95-
}
96-
else
97-
{
98-
bgfx::setViewClear(m_viewId, m_flags, m_rgba, m_depth, m_stencil);
99-
}
59+
bgfx::setViewMode(m_viewId.value(), bgfx::ViewMode::Sequential);
60+
bgfx::setViewClear(m_viewId.value(), flags, rgba, depth, stencil);
61+
bgfx::setViewFrameBuffer(m_viewId.value(), m_handle);
62+
63+
// BGFX will consider the viewport when cleaning the screen, but WebGL always cleans the entire screen.
64+
// That's why we always set the viewport to {0, 0, 1, 1} when cleaning.
65+
bgfx::setViewRect(m_viewId.value(), 0, 0, Width(), Height());
66+
encoder.touch(m_viewId.value());
10067

101-
m_hasViewIdBeenUsed = true;
102-
encoder.touch(m_viewId);
68+
m_bgfxViewPort = {0, 0, 1, 1};
10369
}
10470

10571
void FrameBuffer::SetViewPort(bgfx::Encoder& encoder, float x, float y, float width, float height)
10672
{
107-
if (m_viewPort.X == x && m_viewPort.Y == y && m_viewPort.Width == width && m_viewPort.Height == height)
108-
{
109-
return;
110-
}
111-
112-
m_viewPort = {x, y, width, height};
113-
114-
if (m_hasViewIdBeenUsed)
115-
{
116-
m_viewId = m_context.AcquireNewViewId(encoder);
117-
SetDefaultClearMode(m_viewId, m_handle, m_flags, m_rgba, m_depth, m_stencil);
118-
}
119-
120-
setViewPort(m_viewId, m_viewPort, Width(), Height());
121-
m_hasViewIdBeenUsed = true;
73+
m_desiredViewPort = {x, y, width, height};
74+
SetBgfxViewPort(encoder, m_desiredViewPort);
12275
}
12376

12477
void FrameBuffer::Submit(bgfx::Encoder& encoder, bgfx::ProgramHandle programHandle, uint8_t flags)
12578
{
126-
encoder.submit(m_viewId, programHandle, 0, flags);
127-
m_hasViewIdBeenUsed = true;
79+
SetBgfxViewPort(encoder, m_desiredViewPort);
80+
encoder.submit(m_viewId.value(), programHandle, 0, flags);
12881
}
12982

13083
void FrameBuffer::Blit(bgfx::Encoder& encoder, bgfx::TextureHandle dst, uint16_t dstX, uint16_t dstY, bgfx::TextureHandle src, uint16_t srcX, uint16_t srcY, uint16_t width, uint16_t height)
13184
{
132-
// 1 blit per view, create a new viewId for each blit
133-
// TODO: Really? Why? Is this from the examples or something?
134-
m_viewId = m_context.AcquireNewViewId(encoder);
135-
SetDefaultClearMode(m_viewId, m_handle, m_flags, m_rgba, m_depth, m_stencil);
136-
setViewPort(m_viewId, m_viewPort, Width(), Height());
137-
138-
encoder.blit(m_viewId, dst, dstX, dstY, src, srcX, srcY, width, height);
139-
m_hasViewIdBeenUsed = true;
85+
//In order for Blit to work properly we need to force the creation of a new ViewID.
86+
SetBgfxViewPort(encoder, m_desiredViewPort);
87+
encoder.blit(m_viewId.value(), dst, dstX, dstY, src, srcX, srcY, width, height);
14088
}
14189

14290
void FrameBuffer::SetStencil(bgfx::Encoder& encoder, uint32_t stencilState)
@@ -159,6 +107,27 @@ namespace Babylon::Graphics
159107
m_disposed = true;
160108
}
161109

110+
void FrameBuffer::SetBgfxViewPort(bgfx::Encoder& encoder, const ViewPort& viewPort)
111+
{
112+
if (m_viewId.has_value() && viewPort.Equals(m_bgfxViewPort))
113+
{
114+
return;
115+
}
116+
117+
m_viewId = m_context.AcquireNewViewId(encoder);
118+
119+
m_bgfxViewPort = viewPort;
120+
121+
bgfx::setViewMode(m_viewId.value(), bgfx::ViewMode::Sequential);
122+
bgfx::setViewClear(m_viewId.value(), BGFX_CLEAR_NONE, 0, 1.0f, 0);
123+
bgfx::setViewFrameBuffer(m_viewId.value(), m_handle);
124+
bgfx::setViewRect(m_viewId.value(),
125+
static_cast<uint16_t>(m_bgfxViewPort.X * Width()),
126+
static_cast<uint16_t>(m_bgfxViewPort.Y * Height()),
127+
static_cast<uint16_t>(m_bgfxViewPort.Width * Width()),
128+
static_cast<uint16_t>(m_bgfxViewPort.Height * Height()));
129+
}
130+
162131
bool ViewPort::Equals(const ViewPort& other) const
163132
{
164133
return std::abs(X - other.X) < std::numeric_limits<float>::epsilon() &&

0 commit comments

Comments
 (0)