Usable OpenGL ES

This commit is contained in:
2024-08-22 17:54:26 +02:00
parent dd16a02045
commit 511802bdbd
6 changed files with 107 additions and 51 deletions
-7
View File
@@ -80,13 +80,6 @@ if(COLOR_MANAGMENT)
target_compile_definitions(tenmon PRIVATE "COLOR_MANAGMENT") target_compile_definitions(tenmon PRIVATE "COLOR_MANAGMENT")
endif(COLOR_MANAGMENT) endif(COLOR_MANAGMENT)
# not ready yet
#option(USE_OPENGLES ON)
if(USE_OPENGLES)
target_compile_definitions(tenmon PRIVATE "NOU_GLES_CONTEXT")
endif(USE_OPENGLES)
if(UNIX AND NOT APPLE) if(UNIX AND NOT APPLE)
target_include_directories(tenmon PRIVATE ${GIO_INCLUDE_DIRS}) target_include_directories(tenmon PRIVATE ${GIO_INCLUDE_DIRS})
endif() endif()
+31 -13
View File
@@ -16,6 +16,7 @@
#include <QElapsedTimer> #include <QElapsedTimer>
int FILTERING = 1; int FILTERING = 1;
bool OpenGLES = false;
struct RawImageType struct RawImageType
{ {
@@ -50,6 +51,13 @@ RawImageType getRawImageType(const RawImage *img)
type.textureFormat = QOpenGLTexture::R32F; type.textureFormat = QOpenGLTexture::R32F;
type.dataType = QOpenGLTexture::Float32; type.dataType = QOpenGLTexture::Float32;
break; break;
case RawImage::FLOAT16:
if(img->channels() >= 3)
type.textureFormat = QOpenGLTexture::RGBA16F;
else
type.textureFormat = QOpenGLTexture::R16F;
type.dataType = QOpenGLTexture::Float16;
break;
default: default:
qWarning() << "Invalid format" << img->type(); qWarning() << "Invalid format" << img->type();
break; break;
@@ -128,9 +136,11 @@ void ImageWidget::setImage(std::shared_ptr<RawImage> image, int index)
m_image->allocateStorage(); m_image->allocateStorage();
m_image->setMinMagFilters(QOpenGLTexture::LinearMipMapLinear, QOpenGLTexture::Linear); m_image->setMinMagFilters(QOpenGLTexture::LinearMipMapLinear, QOpenGLTexture::Linear);
m_image->setWrapMode(QOpenGLTexture::ClampToEdge); m_image->setWrapMode(QOpenGLTexture::ClampToEdge);
m_image->setBorderColor(0, 0, 0, 0); //m_image->setBorderColor(0, 0, 0, 0);
m_image->setData(0, rawImageType.pixelFormat, rawImageType.dataType, (const void*)image->data(), m_transferOptions.get()); m_image->setData(0, rawImageType.pixelFormat, rawImageType.dataType, (const void*)image->data());
m_image->generateMipMaps(); //m_image->generateMipMaps();
m_image->bind();
f->glGenerateMipmap(GL_TEXTURE_2D);
qDebug() << "setImage" << timer.elapsed(); qDebug() << "setImage" << timer.elapsed();
m_unit_scale[0] = 1.0f; m_unit_scale[0] = 1.0f;
@@ -203,7 +213,7 @@ void ImageWidget::allocateThumbnails(const QStringList &paths)
m_thumbnailTexture->destroy(); m_thumbnailTexture->destroy();
m_thumbnailTexture->create(); m_thumbnailTexture->create();
m_thumbnailTexture->setFormat(QOpenGLTexture::RGBA16_UNorm); m_thumbnailTexture->setFormat(QOpenGLTexture::RGBA16F);
m_thumbnailTexture->setSize(THUMB_SIZE, THUMB_SIZE); m_thumbnailTexture->setSize(THUMB_SIZE, THUMB_SIZE);
m_thumbnailTexture->setLayers(std::min((int)paths.size(), m_maxArrayLayers)); m_thumbnailTexture->setLayers(std::min((int)paths.size(), m_maxArrayLayers));
m_thumbnailTexture->allocateStorage(); m_thumbnailTexture->allocateStorage();
@@ -301,7 +311,7 @@ void ImageWidget::thumbnailLoaded(const Image *image)
makeCurrent(); makeCurrent();
const RawImage *raw = image->thumbnail(); const RawImage *raw = image->thumbnail();
if(!raw || !raw->valid())return; if(!raw || !raw->valid())return;
m_thumbnailTexture->setData(0, image->number(), QOpenGLTexture::RGBA, QOpenGLTexture::UInt16, raw->data(), m_transferOptions.get()); m_thumbnailTexture->setData(0, image->number(), QOpenGLTexture::RGBA, QOpenGLTexture::Float16, raw->data());
float a = raw->thumbAspect(); float a = raw->thumbAspect();
int sizes[3] = { std::max(1, a > 1.0f ? THUMB_SIZE : (int)(THUMB_SIZE * a)), std::max(1, a < 1.0f ? THUMB_SIZE : (int)(THUMB_SIZE / a)), image->number() }; int sizes[3] = { std::max(1, a > 1.0f ? THUMB_SIZE : (int)(THUMB_SIZE * a)), std::max(1, a < 1.0f ? THUMB_SIZE : (int)(THUMB_SIZE / a)), image->number() };
m_sizesDirty = true; m_sizesDirty = true;
@@ -355,6 +365,7 @@ void ImageWidget::paintGL()
mvp.ortho(rect()); mvp.ortho(rect());
m_thumbnailProgram->setUniformValue("mvp", mvp); m_thumbnailProgram->setUniformValue("mvp", mvp);
fx->glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, m_thumbnailCount); fx->glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, m_thumbnailCount);
m_vaoThumb->release();
QPainter painter(this); QPainter painter(this);
const int w = width()/THUMB_SIZE_BORDER; const int w = width()/THUMB_SIZE_BORDER;
@@ -417,6 +428,7 @@ void ImageWidget::paintGL()
m_program->setUniformValue("srgb", m_srgb); m_program->setUniformValue("srgb", m_srgb);
#endif #endif
f->glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); f->glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
m_vao->release();
} }
} }
@@ -439,19 +451,24 @@ void ImageWidget::initializeGL()
if(fx == nullptr) if(fx == nullptr)
QMessageBox::critical(this, tr("OpenGL error"), tr("Could not initialize OpenGL 3.3 context. Ensure that proper GPU driver is installed.")); QMessageBox::critical(this, tr("OpenGL error"), tr("Could not initialize OpenGL 3.3 context. Ensure that proper GPU driver is installed."));
OpenGLES = context()->isOpenGLES();
auto loadShader = [](const QString &file) auto loadShader = [](const QString &file)
{ {
QFile fr(file); QFile fr(file);
fr.open(QIODevice::ReadOnly); fr.open(QIODevice::ReadOnly);
QByteArray src; QByteArray src;
#ifdef NOU_GLES_CONTEXT if(OpenGLES)
src = "#version 300 es\n" {
"precision highp float;\n" src = "#version 300 es\n"
"precision highp sampler2DArray;\n" "precision highp float;\n"
"#line 1\n"; "precision highp sampler2DArray;\n"
#else "#line 1\n";
src = "#version 330\n#line 1\n"; }
#endif else
{
src = "#version 330\n#line 1\n";
}
src.append(fr.readAll()); src.append(fr.readAll());
return src; return src;
}; };
@@ -551,6 +568,7 @@ void ImageWidget::initializeGL()
m_thumbnailProgram->enableAttributeArray("imageSize_num"); m_thumbnailProgram->enableAttributeArray("imageSize_num");
fx->glVertexAttribIPointer(m_thumbnailProgram->attributeLocation("imageSize_num"), 3, GL_INT, 0, nullptr); fx->glVertexAttribIPointer(m_thumbnailProgram->attributeLocation("imageSize_num"), 3, GL_INT, 0, nullptr);
fx->glVertexAttribDivisor(m_thumbnailProgram->attributeLocation("imageSize_num"), 1); fx->glVertexAttribDivisor(m_thumbnailProgram->attributeLocation("imageSize_num"), 1);
m_vaoThumb->release();
m_image = std::unique_ptr<QOpenGLTexture>(new QOpenGLTexture(QOpenGLTexture::Target2D)); m_image = std::unique_ptr<QOpenGLTexture>(new QOpenGLTexture(QOpenGLTexture::Target2D));
m_image->setFormat(QOpenGLTexture::RGB8U); m_image->setFormat(QOpenGLTexture::RGB8U);
+5 -8
View File
@@ -13,7 +13,6 @@
#include <libxisf.h> #include <libxisf.h>
#include "rawimage.h" #include "rawimage.h"
#include "starfit.h" #include "starfit.h"
#include "wcslib/wcshdr.h"
#ifdef COLOR_MANAGMENT #ifdef COLOR_MANAGMENT
#include <QColorSpace> #include <QColorSpace>
@@ -270,9 +269,6 @@ bool loadFITS(const QString path, ImageInfoData &info, std::shared_ptr<RawImage>
else else
image = RawImage::fromPlanar(img); image = RawImage::fromPlanar(img);
if(image)
image->convertToGLFormat();
break; break;
} }
} }
@@ -343,16 +339,14 @@ bool loadXISF(const QString &path, ImageInfoData &info, std::shared_ptr<RawImage
{ {
image = std::make_shared<RawImage>(tmpImage.width(), tmpImage.height(), 1, type); image = std::make_shared<RawImage>(tmpImage.width(), tmpImage.height(), 1, type);
std::memcpy(image->data(), tmpImage.imageData(), tmpImage.imageDataSize() / tmpImage.channelCount()); std::memcpy(image->data(), tmpImage.imageData(), tmpImage.imageDataSize() / tmpImage.channelCount());
return true;
} }
else if(tmpImage.channelCount() == 3 || tmpImage.channelCount() == 4) else if(tmpImage.channelCount() == 3 || tmpImage.channelCount() == 4)
{ {
image = RawImage::fromPlanar(tmpImage.imageData(), tmpImage.width(), tmpImage.height(), tmpImage.channelCount(), type); image = RawImage::fromPlanar(tmpImage.imageData(), tmpImage.width(), tmpImage.height(), tmpImage.channelCount(), type);
}
if(image)
{
image->convertToGLFormat();
return true; return true;
} }
return false;
} }
catch (LibXISF::Error &err) catch (LibXISF::Error &err)
{ {
@@ -381,8 +375,10 @@ void LoadRunable::run()
if(!loadImage(m_file, info, rawImage)) if(!loadImage(m_file, info, rawImage))
info.info.append({QObject::tr("Error"), QObject::tr("Failed to load image")}); info.info.append({QObject::tr("Error"), QObject::tr("Failed to load image")});
if(rawImage && !m_thumbnail) if(rawImage && !m_thumbnail)
{ {
rawImage->convertToGLFormat();
timer.start(); timer.start();
rawImage->calcStats(); rawImage->calcStats();
const RawImage::Stats &stats = rawImage->imageStats(); const RawImage::Stats &stats = rawImage->imageStats();
@@ -418,6 +414,7 @@ void LoadRunable::run()
if(QUALITY_RESIZE) if(QUALITY_RESIZE)
rawImage->resize(THUMB_SIZE, THUMB_SIZE); rawImage->resize(THUMB_SIZE, THUMB_SIZE);
rawImage->convertToGLFormat();
rawImage->convertToThumbnail(); rawImage->convertToThumbnail();
} }
QMetaObject::invokeMethod(m_receiver, "thumbnailLoadFinish", Qt::QueuedConnection, Q_ARG(std::shared_ptr<RawImage>, rawImage)); QMetaObject::invokeMethod(m_receiver, "thumbnailLoadFinish", Qt::QueuedConnection, Q_ARG(std::shared_ptr<RawImage>, rawImage));
+26 -13
View File
@@ -4,26 +4,39 @@
#include <QTranslator> #include <QTranslator>
#include <stdlib.h> #include <stdlib.h>
/*float h2f(unsigned short h)
{
unsigned int
return f;
}*/
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
#ifdef __linux__ #ifdef __linux__
setenv("LC_NUMERIC", "C", 1); setenv("LC_NUMERIC", "C", 1);
#endif #endif
bool useGLES = false;
for(int i = 0; i < argc; i++)
if(std::strcmp("-gles", argv[i]) == 0)
{
useGLES = true;
}
QSurfaceFormat format; QSurfaceFormat format;
#ifdef NOU_GLES_CONTEXT if(useGLES)
format.setMajorVersion(3); {
format.setMinorVersion(0); format.setMajorVersion(3);
format.setRenderableType(QSurfaceFormat::OpenGLES); format.setMinorVersion(0);
printf("OpenGL ES\n"); format.setRenderableType(QSurfaceFormat::OpenGLES);
qDebug() << "Requesting OpenGL ES"; }
#else else
format.setMajorVersion(3); {
format.setMinorVersion(3); format.setMajorVersion(3);
//format.setOption(QSurfaceFormat::DebugContext); format.setMinorVersion(3);
format.setProfile(QSurfaceFormat::OpenGLContextProfile::CoreProfile); //format.setOption(QSurfaceFormat::DebugContext);
printf("OpenGL\n"); format.setProfile(QSurfaceFormat::OpenGLContextProfile::CoreProfile);
#endif }
QSurfaceFormat::setDefaultFormat(format); QSurfaceFormat::setDefaultFormat(format);
QApplication a(argc, argv); QApplication a(argc, argv);
+44 -10
View File
@@ -2,12 +2,16 @@
#include <QDebug> #include <QDebug>
#include <cstring> #include <cstring>
#include <QElapsedTimer> #include <QElapsedTimer>
#include <QFloat16>
using F16 = qfloat16;
int THUMB_SIZE = 128; int THUMB_SIZE = 128;
int THUMB_SIZE_BORDER = 138; int THUMB_SIZE_BORDER = 138;
int THUMB_SIZE_BORDER_Y = 158; int THUMB_SIZE_BORDER_Y = 158;
double SATURATION = 0.95; double SATURATION = 0.95;
bool QUALITY_RESIZE = true; bool QUALITY_RESIZE = true;
extern bool OpenGLES;
#ifdef __SSE2__ #ifdef __SSE2__
template<typename T, int ch> template<typename T, int ch>
@@ -21,6 +25,7 @@ size_t RawImage::typeSize(RawImage::DataType type)
case RawImage::UINT8: case RawImage::UINT8:
return 1; return 1;
case RawImage::UINT16: case RawImage::UINT16:
case RawImage::FLOAT16:
return 2; return 2;
case RawImage::UINT32: case RawImage::UINT32:
case RawImage::FLOAT32: case RawImage::FLOAT32:
@@ -338,7 +343,7 @@ RawImage::DataType RawImage::type() const
uint32_t RawImage::norm() const uint32_t RawImage::norm() const
{ {
switch(m_type) switch(m_origType)
{ {
case UINT8: case UINT8:
return UINT8_MAX; return UINT8_MAX;
@@ -404,10 +409,10 @@ void RawImage::convertToThumbnail()
if(m_thumbAspect == 0.0f) if(m_thumbAspect == 0.0f)
m_thumbAspect = (float)width() / height(); m_thumbAspect = (float)width() / height();
std::unique_ptr<PixelType[]> outptr = std::make_unique<PixelType[]>(THUMB_SIZE * THUMB_SIZE * 4 * sizeof(uint16_t)); std::unique_ptr<PixelType[]> outptr = std::make_unique<PixelType[]>(THUMB_SIZE * THUMB_SIZE * 4 * sizeof(qfloat16));
uint16_t *out = reinterpret_cast<uint16_t*>(outptr.get()); F16 *out = reinterpret_cast<F16*>(outptr.get());
auto loop = [&](uint16_t *out, auto *in, auto scale) auto loop = [&](F16 *out, auto *in, float scale)
{ {
for(int i=0; i<THUMB_SIZE; i++) for(int i=0; i<THUMB_SIZE; i++)
{ {
@@ -426,7 +431,7 @@ void RawImage::convertToThumbnail()
out[idx + 1] = in[idx2 + 1] * scale;; out[idx + 1] = in[idx2 + 1] * scale;;
out[idx + 2] = in[idx2 + 2] * scale;; out[idx + 2] = in[idx2 + 2] * scale;;
} }
out[idx + 3] = UINT16_MAX; out[idx + 3] = 1.0f;
} }
} }
}; };
@@ -434,16 +439,19 @@ void RawImage::convertToThumbnail()
switch(m_type) switch(m_type)
{ {
case UINT8: case UINT8:
loop(out, reinterpret_cast<uint8_t*>(m_pixels.get()), 256); loop(out, reinterpret_cast<uint8_t*>(m_pixels.get()), 1.0f/UINT8_MAX);
break; break;
case UINT16: case UINT16:
loop(out, reinterpret_cast<uint16_t*>(m_pixels.get()), 1); loop(out, reinterpret_cast<uint16_t*>(m_pixels.get()), 1.0f/UINT16_MAX);
break; break;
case UINT32: case UINT32:
loop(out, reinterpret_cast<uint32_t*>(m_pixels.get()), UINT16_MAX/(float)UINT32_MAX); loop(out, reinterpret_cast<uint32_t*>(m_pixels.get()), (float)(1.0/UINT32_MAX));
break;
case FLOAT16:
loop(out, reinterpret_cast<F16*>(m_pixels.get()), 1.0f);
break; break;
case FLOAT32: case FLOAT32:
loop(out, reinterpret_cast<float*>(m_pixels.get()), 65535.0); loop(out, reinterpret_cast<float*>(m_pixels.get()), 1.0f);
break; break;
default: default:
qWarning() << "FLOAT64 should not happend"; qWarning() << "FLOAT64 should not happend";
@@ -455,7 +463,7 @@ void RawImage::convertToThumbnail()
m_height = THUMB_SIZE; m_height = THUMB_SIZE;
m_ch = 4; m_ch = 4;
m_channels = 3; m_channels = 3;
m_type = UINT16; m_type = FLOAT16;
} }
void RawImage::convertToGLFormat() void RawImage::convertToGLFormat()
@@ -483,6 +491,17 @@ void RawImage::convertToGLFormat()
for(size_t i = 0; i < s; i++) for(size_t i = 0; i < s; i++)
dst[i] = src[i]; dst[i] = src[i];
} }
else if(OpenGLES && m_type == UINT16)
{
m_original = std::move(m_pixels);
allocate(m_width, m_height, m_channels, FLOAT16);
m_origType = UINT16;
F16 *dst = reinterpret_cast<F16*>(m_pixels.get());
uint16_t *src = reinterpret_cast<uint16_t*>(m_original.get());
for(size_t i = 0; i < s; i++)
dst[i] = src[i] / (float)UINT16_MAX;
}
} }
float RawImage::thumbAspect() const float RawImage::thumbAspect() const
@@ -571,6 +590,21 @@ bool RawImage::pixel(int x, int y, double &r, double &g, double &b) const
} }
break; break;
} }
case FLOAT16:
{
const F16 *v = static_cast<const F16*>(origData(y, x));
if(m_channels == 1)
{
r = g = b = *v;
}
else
{
r = v[0];
g = v[1];
b = v[2];
}
break;
}
} }
return true; return true;
} }
+1
View File
@@ -45,6 +45,7 @@ public:
UINT8, UINT8,
UINT16, UINT16,
UINT32, UINT32,
FLOAT16,
FLOAT32, FLOAT32,
FLOAT64, FLOAT64,
}; };