tahoma2d/toonz/sources/stdfx/shadingcontext.cpp

441 lines
13 KiB
C++
Raw Normal View History

2016-03-19 06:57:51 +13:00
// Glew include
#include <GL/glew.h>
// TnzCore includes
#include "tgl.h"
// Qt includes
#include <QCoreApplication>
#include <QThread>
#include <QDateTime>
2017-07-01 16:51:18 +12:00
#include <QOpenGLFramebufferObject>
#include <QOpenGLShaderProgram>
#include <QOpenGLContext>
2017-07-01 16:51:18 +12:00
#include <QOffscreenSurface>
#include <QOpenGLWidget>
2016-03-19 06:57:51 +13:00
// STD includes
#include <map>
#include <memory>
#include "stdfx/shadingcontext.h"
//*****************************************************************
// Local Namespace stuff
//*****************************************************************
2016-06-15 18:43:10 +12:00
namespace {
2016-03-19 06:57:51 +13:00
2017-07-01 16:51:18 +12:00
typedef std::unique_ptr<QOpenGLContext> QOpenGLContextP;
typedef std::unique_ptr<QOpenGLFramebufferObject> QOpenGLFramebufferObjectP;
typedef std::unique_ptr<QOpenGLShaderProgram> QOpenGLShaderProgramP;
2016-03-19 06:57:51 +13:00
struct CompiledShader {
2017-07-01 16:51:18 +12:00
QOpenGLShaderProgramP m_program;
2016-06-15 18:43:10 +12:00
QDateTime m_lastModified;
2016-03-19 06:57:51 +13:00
public:
2016-06-15 18:43:10 +12:00
CompiledShader() {}
CompiledShader(const CompiledShader &) { assert(!m_program.get()); }
2016-03-19 06:57:51 +13:00
};
2016-06-15 18:43:10 +12:00
} // namespace
2016-03-19 06:57:51 +13:00
2017-07-01 16:51:18 +12:00
TQOpenGLWidget::TQOpenGLWidget() {}
void TQOpenGLWidget::initializeGL() {
2017-10-11 15:40:34 +13:00
QOffscreenSurface *surface = new QOffscreenSurface();
// context()->create();
// context()->makeCurrent(surface);
2017-07-01 16:51:18 +12:00
}
2016-03-19 06:57:51 +13:00
//*****************************************************************
// ShadingContext::Imp definition
//*****************************************************************
struct ShadingContext::Imp {
2017-10-11 15:40:34 +13:00
QOpenGLContextP m_context; //!< OpenGL context.
QOpenGLFramebufferObjectP m_fbo; //!< Output buffer.
2017-07-01 16:51:18 +12:00
QOffscreenSurface *m_surface;
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
std::map<QString,
CompiledShader>
m_shaderPrograms; //!< Shader Programs stored in the context.
//! \warning Values have \p unique_ptr members.
2016-03-19 06:57:51 +13:00
public:
2016-06-15 18:43:10 +12:00
Imp();
2016-03-19 06:57:51 +13:00
2017-07-01 16:51:18 +12:00
static QSurfaceFormat format();
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
void initMatrix(int lx, int ly);
2016-03-19 06:57:51 +13:00
private:
2016-06-15 18:43:10 +12:00
// Not copyable
Imp(const Imp &);
Imp &operator=(const Imp &);
2016-03-19 06:57:51 +13:00
};
//--------------------------------------------------------
2017-10-11 15:40:34 +13:00
ShadingContext::Imp::Imp() : m_context(new QOpenGLContext()), m_surface() {}
2016-03-19 06:57:51 +13:00
//--------------------------------------------------------
2017-07-01 16:51:18 +12:00
QSurfaceFormat ShadingContext::Imp::format() {
QSurfaceFormat fmt;
2016-03-19 06:57:51 +13:00
#ifdef MACOSX
2016-06-15 18:43:10 +12:00
fmt.setVersion(3, 2);
2017-08-09 16:54:55 +12:00
fmt.setProfile(QSurfaceFormat::CompatibilityProfile);
2016-03-19 06:57:51 +13:00
#endif
2016-06-15 18:43:10 +12:00
return fmt;
2016-03-19 06:57:51 +13:00
}
//--------------------------------------------------------
2016-06-15 18:43:10 +12:00
void ShadingContext::Imp::initMatrix(int lx, int ly) {
glViewport(0, 0, lx, ly);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0, lx, 0, ly);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
2016-03-19 06:57:51 +13:00
}
//*****************************************************************
// ShadingContext implementation
//*****************************************************************
2017-10-11 15:40:34 +13:00
ShadingContext::ShadingContext(QOffscreenSurface *surface) : m_imp(new Imp) {
m_imp->m_surface = surface;
m_imp->m_surface->create();
QSurfaceFormat format;
m_imp->m_context->setFormat(format);
m_imp->m_context->create();
m_imp->m_context->makeCurrent(m_imp->m_surface);
// m_imp->m_pixelBuffer->context()->create();
// m_imp->m_fbo(new QOpenGLFramebufferObject(1, 1));
2016-06-15 18:43:10 +12:00
makeCurrent();
if( GLEW_VERSION_3_2 ) {
glewExperimental = GL_TRUE;
}
2016-06-15 18:43:10 +12:00
glewInit();
doneCurrent();
2016-03-19 06:57:51 +13:00
}
//--------------------------------------------------------
ShadingContext::~ShadingContext() {
2016-08-04 19:23:36 +12:00
// Destructor of QGLPixelBuffer calls QOpenGLContext::makeCurrent()
// internally,
// so the current thread must be the owner of QGLPixelBuffer context,
// when the destructor of m_imp->m_context is called.
m_imp->m_context->moveToThread(QThread::currentThread());
}
2016-03-19 06:57:51 +13:00
//--------------------------------------------------------
2016-06-15 18:43:10 +12:00
ShadingContext::Support ShadingContext::support() {
2017-10-11 15:40:34 +13:00
// return !QGLPixelBuffer::hasOpenGLPbuffers()
2017-07-01 16:51:18 +12:00
// ? NO_PIXEL_BUFFER
2017-10-11 15:40:34 +13:00
// : !QOpenGLShaderProgram::hasOpenGLShaderPrograms() ? NO_SHADERS :
// OK;
return !QOpenGLShaderProgram::hasOpenGLShaderPrograms() ? NO_SHADERS : OK;
2016-03-19 06:57:51 +13:00
}
//--------------------------------------------------------
2017-07-01 16:51:18 +12:00
bool ShadingContext::isValid() const { return m_imp->m_context->isValid(); }
2016-03-19 06:57:51 +13:00
//--------------------------------------------------------
/*
QGLFormat ShadingContext::defaultFormat(int channelsSize)
{
QGL::FormatOptions opts =
QGL::SingleBuffer |
QGL::NoAccumBuffer |
2016-06-15 18:43:10 +12:00
QGL::NoDepthBuffer | // I guess it could be
necessary to let at least
QGL::NoOverlay | // the depth buffer
enabled... Fragment shaders could
2016-03-19 06:57:51 +13:00
QGL::NoSampleBuffers | // use it...
QGL::NoStencilBuffer |
QGL::NoStereoBuffers;
QGLFormat fmt(opts);
2016-06-15 18:43:10 +12:00
fmt.setDirectRendering(true); // Just to be explicit -
USE HARDWARE ACCELERATION
2016-03-19 06:57:51 +13:00
fmt.setRedBufferSize(channelsSize);
fmt.setGreenBufferSize(channelsSize);
fmt.setBlueBufferSize(channelsSize);
fmt.setAlphaBufferSize(channelsSize);
// TODO: 64-bit mode should be settable here
return fmt;
}
*/
//--------------------------------------------------------
void ShadingContext::makeCurrent() {
2017-10-11 15:40:34 +13:00
m_imp->m_context->moveToThread(QThread::currentThread());
m_imp->m_context.reset(new QOpenGLContext());
2017-10-11 15:40:34 +13:00
QSurfaceFormat format;
m_imp->m_context->setFormat(format);
m_imp->m_context->create();
m_imp->m_context->makeCurrent(m_imp->m_surface);
}
2016-03-19 06:57:51 +13:00
//--------------------------------------------------------
void ShadingContext::doneCurrent() {
m_imp->m_context->moveToThread(0);
2017-07-01 16:51:18 +12:00
m_imp->m_context->doneCurrent();
}
2016-03-19 06:57:51 +13:00
//--------------------------------------------------------
2016-06-15 18:43:10 +12:00
void ShadingContext::resize(int lx, int ly,
2017-07-01 16:51:18 +12:00
const QOpenGLFramebufferObjectFormat &fmt) {
2016-06-15 18:43:10 +12:00
if (m_imp->m_fbo.get() && m_imp->m_fbo->width() == lx &&
m_imp->m_fbo->height() == ly && m_imp->m_fbo->format() == fmt)
return;
if (lx == 0 || ly == 0) {
m_imp->m_fbo.reset(0);
} else {
2017-10-11 15:40:34 +13:00
bool get = m_imp->m_fbo.get();
QOpenGLContext *currContext = m_imp->m_context->currentContext();
bool yes = false;
if (currContext) bool yes = true;
while (!currContext) currContext = m_imp->m_context->currentContext();
m_imp->m_fbo.reset(new QOpenGLFramebufferObject(lx, ly, fmt));
2016-06-15 18:43:10 +12:00
assert(m_imp->m_fbo->isValid());
m_imp->m_fbo->bind();
}
2016-03-19 06:57:51 +13:00
}
//--------------------------------------------------------
2017-07-01 16:51:18 +12:00
QOpenGLFramebufferObjectFormat ShadingContext::format() const {
QOpenGLFramebufferObject *fbo = m_imp->m_fbo.get();
return fbo ? m_imp->m_fbo->format() : QOpenGLFramebufferObjectFormat();
2016-03-19 06:57:51 +13:00
}
//--------------------------------------------------------
2016-06-15 18:43:10 +12:00
TDimension ShadingContext::size() const {
2017-07-01 16:51:18 +12:00
QOpenGLFramebufferObject *fbo = m_imp->m_fbo.get();
2016-06-15 18:43:10 +12:00
return fbo ? TDimension(fbo->width(), fbo->height()) : TDimension();
2016-03-19 06:57:51 +13:00
}
//--------------------------------------------------------
2016-06-15 18:43:10 +12:00
void ShadingContext::addShaderProgram(const QString &shaderName,
2017-07-01 16:51:18 +12:00
QOpenGLShaderProgram *program) {
2016-06-15 18:43:10 +12:00
std::map<QString, CompiledShader>::iterator st =
m_imp->m_shaderPrograms
.insert(std::make_pair(shaderName, CompiledShader()))
.first;
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
st->second.m_program.reset(program);
2016-03-19 06:57:51 +13:00
}
//--------------------------------------------------------
2016-06-15 18:43:10 +12:00
void ShadingContext::addShaderProgram(const QString &shaderName,
2017-07-01 16:51:18 +12:00
QOpenGLShaderProgram *program,
2016-06-15 18:43:10 +12:00
const QDateTime &lastModified) {
std::map<QString, CompiledShader>::iterator st =
m_imp->m_shaderPrograms
.insert(std::make_pair(shaderName, CompiledShader()))
.first;
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
st->second.m_program.reset(program);
st->second.m_lastModified = lastModified;
2016-03-19 06:57:51 +13:00
}
//--------------------------------------------------------
2016-06-15 18:43:10 +12:00
bool ShadingContext::removeShaderProgram(const QString &shaderName) {
return (m_imp->m_shaderPrograms.erase(shaderName) > 0);
2016-03-19 06:57:51 +13:00
}
//--------------------------------------------------------
2017-07-01 16:51:18 +12:00
QOpenGLShaderProgram *ShadingContext::shaderProgram(
2016-06-15 18:43:10 +12:00
const QString &shaderName) const {
std::map<QString, CompiledShader>::iterator st =
m_imp->m_shaderPrograms.find(shaderName);
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
return (st != m_imp->m_shaderPrograms.end()) ? st->second.m_program.get() : 0;
2016-03-19 06:57:51 +13:00
}
//--------------------------------------------------------
2016-06-15 18:43:10 +12:00
QDateTime ShadingContext::lastModified(const QString &shaderName) const {
std::map<QString, CompiledShader>::iterator st =
m_imp->m_shaderPrograms.find(shaderName);
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
return (st != m_imp->m_shaderPrograms.end()) ? st->second.m_lastModified
: QDateTime();
2016-03-19 06:57:51 +13:00
}
//--------------------------------------------------------
2017-07-01 16:51:18 +12:00
std::pair<QOpenGLShaderProgram *, QDateTime> ShadingContext::shaderData(
2016-06-15 18:43:10 +12:00
const QString &shaderName) const {
std::map<QString, CompiledShader>::iterator st =
m_imp->m_shaderPrograms.find(shaderName);
return (st != m_imp->m_shaderPrograms.end())
? std::make_pair(st->second.m_program.get(),
st->second.m_lastModified)
2017-07-01 16:51:18 +12:00
: std::make_pair((QOpenGLShaderProgram *)0, QDateTime());
2016-03-19 06:57:51 +13:00
}
//--------------------------------------------------------
2016-06-15 18:43:10 +12:00
GLuint ShadingContext::loadTexture(const TRasterP &src, GLuint texUnit) {
glActiveTexture(GL_TEXTURE0 + texUnit);
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
GLuint texId;
glGenTextures(1, &texId);
glBindTexture(GL_TEXTURE_2D, texId);
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
GL_CLAMP); // These must be used on a bound texture,
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,
GL_CLAMP); // and are remembered in the OpenGL context.
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
GL_NEAREST); // They can be set here, no need for
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
GL_NEAREST); // the user to do it.
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
glPixelStorei(GL_UNPACK_ROW_LENGTH, src->getWrap());
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
GLenum chanType = TRaster32P(src) ? GL_UNSIGNED_BYTE : GL_UNSIGNED_SHORT;
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
glTexImage2D(GL_TEXTURE_2D,
0, // one level only
GL_RGBA, // pixel channels count
src->getLx(), // width
src->getLy(), // height
0, // border size
TGL_FMT, // pixel format
chanType, // channel data type
(GLvoid *)src->getRawData());
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
assert(glGetError() == GL_NO_ERROR);
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
return texId;
2016-03-19 06:57:51 +13:00
}
//----------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
void ShadingContext::unloadTexture(GLuint texId) {
glDeleteTextures(1, &texId);
2016-03-19 06:57:51 +13:00
}
//--------------------------------------------------------
2016-06-15 18:43:10 +12:00
void ShadingContext::draw(const TRasterP &dst) {
assert("ShadingContext::resize() must be invoked at least once before this" &&
m_imp->m_fbo.get());
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
int lx = dst->getLx(),
ly = dst->getLy(); // NOTE: We're not using m_imp->m_fbo's size, since
// it could be possibly greater than the required
// destination surface.
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
m_imp->initMatrix(lx, ly); // This call sets the OpenGL viewport to this
// size - and matches (1, 1) to dst's (lx, ly)
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
{
glBegin(GL_QUADS);
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
glVertex2f(0.0, 0.0);
glVertex2f(lx, 0.0);
glVertex2f(lx, ly);
glVertex2f(0.0, ly);
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
glEnd();
}
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
glPixelStorei(GL_PACK_ROW_LENGTH, dst->getWrap());
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
// Read the fbo to dst
if (TRaster32P ras32 = dst)
glReadPixels(0, 0, lx, ly, GL_BGRA_EXT, GL_UNSIGNED_BYTE,
dst->getRawData());
else {
assert(TRaster64P(dst));
glReadPixels(0, 0, lx, ly, GL_BGRA_EXT, GL_UNSIGNED_SHORT,
dst->getRawData());
}
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
assert(glGetError() == GL_NO_ERROR);
2016-03-19 06:57:51 +13:00
}
//--------------------------------------------------------
2016-06-15 18:43:10 +12:00
void ShadingContext::transformFeedback(int varyingsCount,
const GLsizeiptr *varyingSizes,
GLvoid **bufs) {
// Generate buffer objects
std::vector<GLuint> bufferObjectNames(varyingsCount, 0);
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
glGenBuffers(varyingsCount, &bufferObjectNames[0]);
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
for (int v = 0; v != varyingsCount; ++v) {
glBindBuffer(GL_ARRAY_BUFFER, bufferObjectNames[v]);
glBufferData(GL_ARRAY_BUFFER, varyingSizes[v], bufs[v], GL_STATIC_READ);
glBindBuffer(GL_ARRAY_BUFFER, 0);
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, v, bufferObjectNames[v]);
}
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
// Draw
GLuint Query = 0;
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
glGenQueries(1, &Query);
{
// Disable rasterization, vertices processing only!
glEnable(GL_RASTERIZER_DISCARD);
glBeginQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, Query);
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
glBeginTransformFeedback(GL_POINTS);
glBegin(GL_POINTS);
glVertex2f(0.0f, 0.0f);
glEnd();
glEndTransformFeedback();
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
glEndQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN);
glDisable(GL_RASTERIZER_DISCARD);
}
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
GLint count = 0;
glGetQueryObjectiv(Query, GL_QUERY_RESULT, &count);
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
glDeleteQueries(1, &Query);
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
// Retrieve transformed data
for (int v = 0; v != varyingsCount; ++v) {
glBindBuffer(GL_ARRAY_BUFFER, bufferObjectNames[v]);
glGetBufferSubData(GL_ARRAY_BUFFER, 0, varyingSizes[v], bufs[v]);
}
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
glBindBuffer(GL_ARRAY_BUFFER, 0);
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
// Delete buffer objects
glDeleteBuffers(varyingsCount, &bufferObjectNames[0]);
2016-03-19 06:57:51 +13:00
}