Skip to content

Commit 28840fb

Browse files
committed
fix: size backbuffer readbacks from the backbuffer, not the viewport
Resizing the window during startup aborted the game: terminate called after throwing an instance of 'std::runtime_error' what(): GetBackBufferData: data array too small for requested region GetBackBufferData()'s no-rect overload reads the WHOLE backbuffer, and CNA validates the array against PresentationParameters.BackBufferWidth/Height. All three one-shot captures here sized their arrays from Viewport instead. Those are not the same rectangle. EasyGL runs a FixedHeightDynamicWidth virtual resolution, so on a resize the Viewport becomes the logical size -- height pinned to the virtual 480, width following the window's aspect -- while the backbuffer stays at 800x480. Confirmed live with CNA_BACKBUFFER_READ_TRACE: after a resize, backbuffer=800x480 viewport=802x480. Widen the window and the array is merely oversized; make it narrower than 800:480 and it is too small, and the uncaught std::runtime_error is a hard SIGABRT. The terrain diagnostic had a second instance of the same mistake: its 5x5 grid of single-pixel sample rectangles was also derived from the Viewport, and CNA bounds-checks those against the backbuffer too, so a Viewport wider than the backbuffer threw std::out_of_range from a different line. Ask for the backbuffer's own size through a small shared helper, which is what these calls actually read. elementCount is then always exactly backBufferWidth * backBufferHeight -- the quantity CNA compares against -- so the mismatch is unreachable by construction rather than merely unlikely. The engine side of the resize story (EasyGL applying the logical size as the physical GL viewport, and an SDL3 window-sync timeout thrown as a fatal exception) was fixed separately in CNA and is not this commit's subject.
1 parent c32bc8f commit 28840fb

1 file changed

Lines changed: 34 additions & 9 deletions

File tree

src/GalaxyEggbertCNA/GalaxyEggbertGame.cpp

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,29 @@ namespace GalaxyEggbert::CNA
272272
}
273273
}
274274

275+
namespace
276+
{
277+
// GetBackBufferData()'s no-rect overload reads the WHOLE backbuffer, and CNA sizes
278+
// that read from PresentationParameters.BackBufferWidth/Height. The three one-shot
279+
// captures below used to size their arrays from Viewport instead. Those are not the
280+
// same rectangle: EasyGL runs a FixedHeightDynamicWidth virtual resolution, so on a
281+
// window resize the Viewport becomes the LOGICAL size (height pinned to 480, width
282+
// following the window's aspect) while the backbuffer stays at its 800x480 virtual
283+
// resolution. Resize the window narrower than 800:480 mid-startup and the array came
284+
// out smaller than the backbuffer, so CNA threw "GetBackBufferData: data array too
285+
// small for requested region" -- an uncaught std::runtime_error, i.e. a hard SIGABRT
286+
// (user-reported 2026-08-21, reproduced by resizing during startup).
287+
//
288+
// Ask for the backbuffer's own size, which is what the call actually reads.
289+
void GetBackBufferSize(
290+
const Microsoft::Xna::Framework::Graphics::GraphicsDevice& device, int& w, int& h)
291+
{
292+
const auto& pp = device.getPresentationParametersProperty();
293+
w = static_cast<int>(pp.getBackBufferWidthProperty());
294+
h = static_cast<int>(pp.getBackBufferHeightProperty());
295+
}
296+
}
297+
275298
GalaxyEggbertGame::GalaxyEggbertGame()
276299
{
277300
Game::getWindowProperty().setTitleProperty("Galaxy Eggbert (CNA)");
@@ -3661,9 +3684,13 @@ namespace GalaxyEggbert::CNA
36613684
{
36623685
terrainPixelPrinted = true;
36633686
terrainPixelPrintedFrame_ = drawFrameIndex_;
3664-
const auto& viewport = device.getViewportProperty();
3665-
const int w = viewport.getWidthProperty();
3666-
const int h = viewport.getHeightProperty();
3687+
// Backbuffer, not Viewport -- see GetBackBufferSize()'s comment. This site
3688+
// needs it for BOTH readbacks below: the whole-backbuffer capture, and the
3689+
// 5x5 single-pixel grid, whose sample rectangles CNA validates against the
3690+
// backbuffer bounds (a Viewport wider than the backbuffer made those throw
3691+
// std::out_of_range instead).
3692+
int w = 0, h = 0;
3693+
GetBackBufferSize(device, w, h);
36673694

36683695
// Sample a 5x5 grid over the central 60% of the screen —
36693696
// more robust than one center pixel, which can miss terrain
@@ -4182,9 +4209,8 @@ namespace GalaxyEggbert::CNA
41824209
if (!hudScreenshotWritten && drawFrameIndex_ > terrainPixelPrintedFrame_)
41834210
{
41844211
hudScreenshotWritten = true;
4185-
const auto& viewport = device.getViewportProperty();
4186-
const int w = viewport.getWidthProperty();
4187-
const int h = viewport.getHeightProperty();
4212+
int w = 0, h = 0;
4213+
GetBackBufferSize(device, w, h);
41884214
std::vector<Microsoft::Xna::Framework::Color> backBuffer(
41894215
static_cast<std::size_t>(w) * static_cast<std::size_t>(h),
41904216
Microsoft::Xna::Framework::Color(0, 0, 0, 0));
@@ -4207,9 +4233,8 @@ namespace GalaxyEggbert::CNA
42074233
if (goldenCaptureAwaitingDraw_ &&
42084234
goldenCaptureNextIndex_ < kGoldenCaptureCount)
42094235
{
4210-
const auto& viewport = device.getViewportProperty();
4211-
const int w = viewport.getWidthProperty();
4212-
const int h = viewport.getHeightProperty();
4236+
int w = 0, h = 0;
4237+
GetBackBufferSize(device, w, h);
42134238
std::vector<Microsoft::Xna::Framework::Color> backBuffer(
42144239
static_cast<std::size_t>(w) * static_cast<std::size_t>(h),
42154240
Microsoft::Xna::Framework::Color(0, 0, 0, 0));

0 commit comments

Comments
 (0)