Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions lib/src/gpu/uhdr_gl_utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,11 @@ void uhdr_opengl_ctxt::init_opengl_ctxt() {
"eglMakeCurrent() failed")
#undef RET_IF_TRUE

// Image buffers handed to and read from this context are tightly packed (rows are w * bpp
// bytes), so texture uploads and read backs must not assume the default 4-byte row alignment.
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glPixelStorei(GL_PACK_ALIGNMENT, 1);

setup_quad();
}

Expand Down Expand Up @@ -184,9 +189,7 @@ GLuint uhdr_opengl_ctxt::create_texture(uhdr_img_fmt_t fmt, int w, int h, void*
glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, w, h * 3 / 2, 0, GL_RED, GL_UNSIGNED_BYTE, data);
break;
case UHDR_IMG_FMT_8bppYCbCr400:
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, w, h, 0, GL_RED, GL_UNSIGNED_BYTE, data);
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
break;
case UHDR_IMG_FMT_32bppRGBA8888:
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
Expand Down Expand Up @@ -343,9 +346,7 @@ void uhdr_opengl_ctxt::read_texture(GLuint* texture, uhdr_img_fmt_t fmt, int w,
} else if (fmt == UHDR_IMG_FMT_64bppRGBAHalfFloat) {
glReadPixels(0, 0, w, h, GL_RGBA, GL_HALF_FLOAT, data);
} else if (fmt == UHDR_IMG_FMT_8bppYCbCr400) {
glPixelStorei(GL_PACK_ALIGNMENT, 1);
glReadPixels(0, 0, w, h, GL_RED, GL_UNSIGNED_BYTE, data);
glPixelStorei(GL_PACK_ALIGNMENT, 4);
}
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glDeleteFramebuffers(1, &frm_buffer);
Expand Down
44 changes: 44 additions & 0 deletions tests/editorhelper_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -498,4 +498,48 @@ INSTANTIATE_TEST_SUITE_P(
UHDR_IMG_FMT_64bppRGBAHalfFloat,
UHDR_IMG_FMT_32bppRGBA8888)));

#ifdef UHDR_ENABLE_GLES
// Planes are tightly packed, so textures must hold exactly the bytes of the buffer for widths
// whose rows are not a multiple of 4 bytes.
TEST(OpenGLContextTest, TextureUploadOfTightlyPackedRows) {
uhdr_opengl_ctxt opengl_ctxt;
opengl_ctxt.init_opengl_ctxt();
if (opengl_ctxt.mErrorStatus.error_code != UHDR_CODEC_OK) {
GTEST_SKIP() << "opengl context unavailable";
}
struct {
uhdr_img_fmt_t fmt;
int rows_per_line; // texture rows per image row, in halves
int bpp;
} formats[] = {
{UHDR_IMG_FMT_8bppYCbCr400, 2, 1}, {UHDR_IMG_FMT_12bppYCbCr420, 3, 1},
{UHDR_IMG_FMT_16bppYCbCr422, 4, 1}, {UHDR_IMG_FMT_24bppYCbCr444, 6, 1},
{UHDR_IMG_FMT_24bppRGB888, 2, 3},
};
const int ht = 8;
for (const auto& f : formats) {
for (int wd = 1; wd <= 10; wd++) {
std::string msg = "format: " + std::to_string(f.fmt) + " width: " + std::to_string(wd);
const int tex_ht = ht * f.rows_per_line / 2;
std::vector<uint8_t> src(static_cast<size_t>(wd) * tex_ht * f.bpp);
for (size_t i = 0; i < src.size(); i++) src[i] = static_cast<uint8_t>(i * 7 + 1);
GLuint texture = opengl_ctxt.create_texture(f.fmt, wd, ht, src.data());
ASSERT_NE(texture, 0u) << msg;
std::vector<uint8_t> dst;
if (f.bpp == 1) {
dst.resize(src.size());
opengl_ctxt.read_texture(&texture, UHDR_IMG_FMT_8bppYCbCr400, wd, tex_ht, dst.data());
} else {
std::vector<uint8_t> rgba(static_cast<size_t>(wd) * tex_ht * 4);
opengl_ctxt.read_texture(&texture, UHDR_IMG_FMT_32bppRGBA8888, wd, tex_ht, rgba.data());
for (size_t i = 0; i < rgba.size(); i += 4) dst.insert(dst.end(), &rgba[i], &rgba[i + 3]);
}
glDeleteTextures(1, &texture);
ASSERT_EQ(opengl_ctxt.mErrorStatus.error_code, UHDR_CODEC_OK) << msg;
ASSERT_EQ(src, dst) << msg;
}
}
}
#endif

} // namespace ultrahdr
Loading