Skip to content

Commit e626fab

Browse files
committed
fix(dds): Fix broken reading of volumetric DDS files by emulating tiles
Fixes #5132. Reading DDS volumetric files used to work, but was broken by PR #4669 last year, the one where we added all the span-oriented API calls. At that time, I did not realize/remember that DDS files could be volumetric, observed that all the (other) volumetric files only supported tiled access, and so in the course of that API refactor, I removed the z parameter from the new read_scanlines API. I don't want to break ABI compatibility again for this, so the solution I came up with in this PR is just to make DDS volume files report themselves as "tiled", with each tile being (width x 1 x 1), i.e. what used to be one scanline, and it all just works out. Signed-off-by: Larry Gritz <lg@larrygritz.com>
1 parent 59a3201 commit e626fab

File tree

1 file changed

+25
-3
lines changed

1 file changed

+25
-3
lines changed

src/dds.imageio/ddsinput.cpp

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -862,6 +862,11 @@ DDSInput::seek_subimage(int subimage, int miplevel)
862862
// detect texture type
863863
if (m_dds.caps.flags2 & DDS_CAPS2_VOLUME) {
864864
m_spec.attribute("textureformat", "Volume Texture");
865+
// Because we don't support reading scanlines from volume textures,
866+
// pretend it's tiled with width x 1 x 1 tiles.
867+
m_spec.tile_width = m_spec.width;
868+
m_spec.tile_height = 1;
869+
m_spec.tile_depth = 1;
865870
} else if (m_dds.caps.flags2 & DDS_CAPS2_CUBEMAP) {
866871
m_spec.attribute("textureformat", "CubeFace Environment");
867872
// check available cube map sides
@@ -1042,12 +1047,29 @@ DDSInput::read_native_tile(int subimage, int miplevel, int x, int y, int z,
10421047
if (!seek_subimage(subimage, miplevel))
10431048
return false;
10441049

1050+
// don't proceed if not tiled
1051+
if (m_spec.tile_width == 0)
1052+
return false;
1053+
1054+
if (m_dds.caps.flags2 & DDS_CAPS2_VOLUME) {
1055+
// This is a 3D volume file. For DDS files, we are emulating tiles,
1056+
// with each scanline as a tile.
1057+
if (m_buf.empty())
1058+
readimg_scanlines();
1059+
// We reported scanlines as tiles, so x must be 0.
1060+
if (x != 0)
1061+
return false;
1062+
size_t size = spec().scanline_bytes();
1063+
size_t offset = size * (size_t(z) * size_t(m_spec.height) + y);
1064+
if (offset + size > m_buf.size()) // Bounds check
1065+
return false;
1066+
memcpy(data, m_buf.data() + offset, size);
1067+
return true;
1068+
}
1069+
10451070
// static ints to keep track of the current cube face and re-seek and
10461071
// re-read face
10471072
static int lastx = -1, lasty = -1, lastz = -1;
1048-
// don't proceed if not a cube map - use scanlines then instead
1049-
if (!(m_dds.caps.flags2 & DDS_CAPS2_CUBEMAP))
1050-
return false;
10511073
// make sure we get the right dimensions
10521074
if (x % m_spec.tile_width || y % m_spec.tile_height
10531075
|| z % m_spec.tile_width)

0 commit comments

Comments
 (0)