What's wrong with my texture data copy?


#1

After updating BSF I get a crash in my texture data copy code:

DataBuffer = bs::PixelData::create(width, height, 1, BS_PIXEL_FORMAT);

uint32_t* destptr = reinterpret_cast<uint32_t*>(DataBuffer->getData());
const uint32_t* source = static_cast<const uint32_t*>(buffer);

const size_t rowElements = DataBuffer->getRowPitch();

for(const auto rect : dirtyRects) {

    const auto lastX = rect.x + rect.width;
    const auto lastY = rect.y + rect.height;

    for(int y = rect.y; y < lastY; ++y) {
        for(int x = rect.x; x < lastX; ++x) {
            destptr[(rowElements * y) + x] = source[(y * width) + x];
        }
    }
}

I did make a few unrelated changes, and now I wasn’t able to quickly find a BSF version that worked. So I’m left wondering what’s wrong with that copy?

Full code: https://github.com/hhyyrylainen/Leviathan/blob/b8ec57d0ad0f9279677e2502ab98b91aa19dc42f/Engine/GUI/GuiView.cpp#L432

GDB output:

Thread 1 "LeviathanEditor" received signal SIGSEGV, Segmentation fault.
0x00007ffff7d00710 in Leviathan::GUI::View::OnPaint (this=0x8a33de0, browser=..., type=<optimized out>, dirtyRects=..., buffer=0x92b0350, width=1280, height=720) at /home/hhyyrylainen/Projects/Leviathan/Engine/GUI/GuiView.cpp:483
483	                    destptr[(rowElements * y) + x] = source[(y * width) + x];
(gdb) p *DataBuffer
$1 = (bs::PixelData) {
  <bs::GpuResourceData> = {
    <bs::IReflectable> = {
      _vptr.IReflectable = 0x7fffef66c8b0 <vtable for bs::PixelData+16>
    }, 
    members of bs::GpuResourceData: 
    mData = 0x8f2c340 '\377' <repeats 200 times>..., 
    mOwnsData = true, 
    mLocked = false
  }, 
  members of bs::PixelData: 
  mExtents = {
    left = 0, 
    top = 0, 
    right = 1280, 
    bottom = 720, 
    front = 0, 
    back = 1
  }, 
  mFormat = bs::PF_BGRA8, 
  mRowPitch = 5120, 
  mSlicePitch = 3686400
}
(gdb) info locals
x = 254
y = 367
lastX = 1018
lastY = 510
rect = <optimized out>
__for_range = <optimized out>
__for_begin = <optimized out>
__for_end = <optimized out>
destptr = 0x8f2c340
source = 0x92b0350
rowElements = <optimized out>
guard = {
  _M_device = 0x8a33e68, 
  _M_owns = true
}
buffSize = <optimized out>
fullOverwrite = false
firstRect = <optimized out>
(gdb) p source[(y * width) + x]
$2 = 4294967295
(gdb) p destptr[(rowElements * y) + x]
value has been optimized out
(gdb) p (unsigned int *) 0x8f2c340 
$3 = (unsigned int *) 0x8f2c340
(gdb) p $3[0]
$4 = 4294967295
(gdb) p $3[(rowElements * y) + x]
value has been optimized out
(gdb) p $3[(5120 * y) + x]
Cannot access memory at address 0x9657738

Everything seems fine except the buffer inside the BSF texture data is too small. Happens both with OpenGL and Vulkan.


#2

The pitch is wrong. The API changed a few days ago and getRowPitch now returns number of bytes rather than number of pixels (returning number of pixels was problematic for compressed formats which group data in blocks rather than pixels).


#3

Ah, okay. Changing the pitch to:
const size_t rowElements = DataBuffer->getRowPitch() / CEF_BYTES_PER_PIXEL; fixed it.