Files
oak-editor/app/render/backend/opengl/opengltexture.cpp
T
itsmattkc 663ae56ac4 more coherent render threading for now
Once again, conceptually this system should work, however it does not seem to
be the most efficient and it wouldn't surprise me if the multithreading was
eventually upgraded to an even more coherent system one day. However for
"core principles" this should be fairly decent.
2019-11-03 04:05:43 +11:00

254 lines
5.8 KiB
C++

/***
Olive - Non-Linear Video Editor
Copyright (C) 2019 Olive Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#include "opengltexture.h"
#include <QDateTime>
#include <QDebug>
#include "render/pixelservice.h"
OpenGLTexture::OpenGLTexture() :
context_(nullptr),
texture_(0),
back_texture_(0),
width_(0),
height_(0),
format_(olive::PIX_FMT_INVALID)
{
}
OpenGLTexture::~OpenGLTexture()
{
Destroy();
}
bool OpenGLTexture::IsCreated() const
{
return (texture_ != 0);
}
void OpenGLTexture::Create(QOpenGLContext *ctx, int width, int height, const olive::PixelFormat &format, void* data)
{
Create(ctx, width, height, format, kSingleBuffer, data);
}
void OpenGLTexture::Create(QOpenGLContext *ctx, int width, int height, const olive::PixelFormat &format, const OpenGLTexture::Type &type, void *data)
{
if (ctx == nullptr) {
qWarning() << "RenderTexture::Create was passed an invalid context";
return;
}
Destroy();
context_ = ctx;
width_ = width;
height_ = height;
format_ = format;
connect(context_, SIGNAL(aboutToBeDestroyed()), this, SLOT(Destroy()));
// Create main texture
CreateInternal(&texture_, data);
if (type == kDoubleBuffer) {
// Create back texture
CreateInternal(&back_texture_, nullptr);
}
}
void OpenGLTexture::Create(QOpenGLContext *ctx, FramePtr frame, const Type &type)
{
Create(ctx, frame->width(), frame->height(), frame->format(), type, frame->data());
}
void OpenGLTexture::Create(QOpenGLContext *ctx, FramePtr frame)
{
Create(ctx, frame, kSingleBuffer);
}
void OpenGLTexture::Destroy()
{
if (context_ != nullptr) {
disconnect(context_, SIGNAL(aboutToBeDestroyed()), this, SLOT(Destroy()));
context_->functions()->glDeleteTextures(1, &texture_);
texture_ = 0;
context_->functions()->glDeleteTextures(1, &back_texture_);
back_texture_ = 0;
context_ = nullptr;
}
}
void OpenGLTexture::Bind()
{
if (context_ == nullptr) {
qWarning() << "RenderTexture::Bind() called with an invalid context";
return;
}
context_->functions()->glBindTexture(GL_TEXTURE_2D, texture_);
}
void OpenGLTexture::Release()
{
if (context_ == nullptr) {
qWarning() << "RenderTexture::Release() called with an invalid context";
return;
}
context_->functions()->glBindTexture(GL_TEXTURE_2D, 0);
}
const int &OpenGLTexture::width() const
{
return width_;
}
const int &OpenGLTexture::height() const
{
return height_;
}
const olive::PixelFormat &OpenGLTexture::format() const
{
return format_;
}
QOpenGLContext *OpenGLTexture::context() const
{
return context_;
}
const GLuint &OpenGLTexture::texture() const
{
return texture_;
}
const GLuint &OpenGLTexture::back_texture() const
{
return back_texture_;
}
void OpenGLTexture::SwapFrontAndBack()
{
GLuint temp = texture_;
texture_ = back_texture_;
back_texture_ = temp;
}
void OpenGLTexture::Upload(const void *data)
{
if (!IsCreated()) {
qWarning() << "RenderTexture::Upload() called while it wasn't created";
return;
}
Bind();
PixelFormatInfo info = PixelService::GetPixelFormatInfo(format_);
context_->functions()->glTexSubImage2D(GL_TEXTURE_2D,
0,
0,
0,
width_,
height_,
info.pixel_format,
info.gl_pixel_type,
data);
Release();
}
uchar *OpenGLTexture::Download() const
{
if (!IsCreated()) {
qWarning() << "RenderTexture::Download() called while it wasn't created";
return nullptr;
}
QOpenGLFunctions* f = context_->functions();
GLuint read_fbo;
f->glGenFramebuffers(1, &read_fbo);
f->glBindFramebuffer(GL_READ_FRAMEBUFFER, read_fbo);
context_->extraFunctions()->glFramebufferTexture2D(
GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture_, 0
);
PixelFormatInfo format_info = PixelService::GetPixelFormatInfo(format_);
uchar* data = new uchar[PixelService::GetBufferSize(format_, width_, height_)];
f->glReadPixels(0, 0, width_, height_, format_info.pixel_format, format_info.gl_pixel_type, data);
f->glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
f->glDeleteFramebuffers(1, &read_fbo);
return data;
}
void OpenGLTexture::CreateInternal(GLuint* tex, void *data)
{
QOpenGLFunctions* f = context_->functions();
// Create texture
f->glGenTextures(1, tex);
// Verify texture
if (texture_ == 0) {
qWarning() << "OpenGL texture creation failed";
return;
}
// Bind texture
f->glBindTexture(GL_TEXTURE_2D, *tex);
// Allocate storage for texture
const PixelFormatInfo& bit_depth = PixelService::GetPixelFormatInfo(format_);
f->glTexImage2D(
GL_TEXTURE_2D,
0,
bit_depth.internal_format,
width_,
height_,
0,
bit_depth.pixel_format,
bit_depth.gl_pixel_type,
data
);
// Set texture filtering to bilinear
f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// Release texture
f->glBindTexture(GL_TEXTURE_2D, 0);
}