Skip to content

Commit 0605638

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 0605638

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)