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