finished prototype for float pix fmt converter

This commit is contained in:
itsmattkc
2019-05-30 21:50:18 +10:00
parent c8fe9c9fc7
commit 707ad3c264
28 changed files with 671 additions and 300 deletions
+1 -3
View File
@@ -67,9 +67,7 @@ void FramebufferObject::Create(QOpenGLContext *ctx, int width, int height)
f->glBindTexture(GL_TEXTURE_2D, texture_);
// allocate storage for texture
const olive::PixelFormatInfo& bit_depth = olive::pixel_formats.at(olive::Global->is_exporting() ?
olive::config.export_bit_depth :
olive::config.playback_bit_depth);
const olive::PixelFormatInfo& bit_depth = olive::pixel_formats.at(olive::Global->effective_bit_depth());
ctx->functions()->glTexImage2D(
GL_TEXTURE_2D,
+296
View File
@@ -0,0 +1,296 @@
#include "imagecache.h"
#include <QDebug>
#include "decoders/pixelformatconverter.h"
#include "global/config.h"
#include "global/global.h"
ImageCache::ImageCache() :
ctx_(nullptr),
width_(0),
height_(0)
{
}
ImageCache::~ImageCache()
{
buffer_array_mutex_.lock();
Clear();
buffer_array_mutex_.unlock();
}
void ImageCache::SetParameters(QOpenGLContext *ctx, int width, int height)
{
buffer_array_mutex_.lock();
ctx_ = ctx;
if (ctx_ != nullptr) {
Q_ASSERT(width > 0 && height > 0);
width_ = width;
height_ = height;
}
Clear();
buffer_array_mutex_.unlock();
}
int ImageCache::RequestBuffer(Ref* r, const BufferType& type, int width, int height)
{
if (type == kTexBuf && (ctx_ == nullptr || width_ == 0 || height_ == 0)) {
qWarning() << "A texture cache request was made without valid parameters [" << ctx_ << width_ << "," << height_ << "]";
return -1;
}
buffer_array_mutex_.lock();
int buffer = RequestBufferInternal(r, type, width, height);
buffer_array_mutex_.unlock();
return buffer;
}
int ImageCache::RequestBufferInternal(Ref *r, const BufferType& type, int width, int height)
{
Q_ASSERT(type != kInvalidBuf);
QList<int>& relinquished = (type == kMemBuf) ? img_relinquished_ : tex_relinquished_;
QList<Ref*>& refs = (type == kMemBuf) ? img_refs_ : tex_refs_;
QList<time_t>& access_times = (type == kMemBuf) ? img_access_times_ : tex_access_times_;
// Try to return a relinquished buffer
if (!relinquished.isEmpty()) {
if (type == kTexBuf) {
int buf_index = relinquished.takeFirst();
refs.replace(buf_index, r);
return buf_index;
} else if (type == kMemBuf) {
// Check for a relinquished buffer with the desired size
//
// TODO consider a database for sorting through these buffers
//
for (int i=0;i<relinquished.size();i++) {
const MemoryBuffer& b = img_buffers_.at(relinquished.at(i));
if (b.width() == width && b.height() == height) {
// This buffer fits, we'll use it
int buffer_index = relinquished.takeAt(i);
refs.replace(buffer_index, r);
return buffer_index;
}
}
}
}
// If no buffer was available, we may have to create a new one
// Check if we have enough memory (according to user-defined limits in the Config), if we don't, try to relinquish an
// old buffer and return that.
if (OutOfMemory()) {
//
// TODO no support for a MemBuf's variable size
//
int least_recent_access = 0;
// Loop through buffers for the oldest accessed buffer
for (int i=1;i<access_times.size();i++) {
if (access_times.at(i) < access_times.at(least_recent_access)
&& refs.at(i) != nullptr) { // ensure this buffer has not been relinquished
least_recent_access = i;
}
}
// Relinquish this buffer
refs.at(least_recent_access)->Relinquish();
refs.replace(least_recent_access, r);
return least_recent_access;
}
// Otherwise, just generate a new buffer
int index = -1;
switch (type) {
case kMemBuf:
index = img_buffers_.size();
img_buffers_.append(MemoryBuffer());
img_buffers_.last().Create(width_, height_, olive::Global->effective_bit_depth());
break;
case kTexBuf:
index = tex_buffers_.size();
tex_buffers_.append(FramebufferObject());
tex_buffers_.last().Create(ctx_, width_, height_);
break;
default:
Q_ASSERT(false);
}
refs.append(r);
access_times.append(time(nullptr));
return index;
}
void ImageCache::RelinquishBuffer(int index, const BufferType &type)
{
buffer_array_mutex_.lock();
switch (type) {
case kMemBuf:
img_refs_.replace(index, nullptr);
img_relinquished_.append(index);
break;
case kTexBuf:
tex_refs_.replace(index, nullptr);
tex_relinquished_.append(index);
break;
default:
qFatal("Invalid buffer type on ImageCache::RelinquishBuffer");
}
buffer_array_mutex_.unlock();
}
void *ImageCache::Buffer(int index, const BufferType &type)
{
switch (type) {
case kMemBuf:
img_access_times_.replace(index, time(nullptr));
return &img_buffers_[index];
case kTexBuf:
tex_access_times_.replace(index, time(nullptr));
return &tex_buffers_[index];
default:
qFatal("Invalid buffer type on ImageCache::Buffer");
}
}
bool ImageCache::OutOfMemory()
{
// TODO actually check if we have any memory or not
return false;
}
void ImageCache::Clear()
{
for (int i=0;i<img_refs_.size();i++) {
img_refs_.at(i)->Relinquish();
}
for (int i=0;i<tex_refs_.size();i++) {
tex_refs_.at(i)->Relinquish();
}
img_refs_.clear();
tex_refs_.clear();
img_buffers_.clear();
tex_buffers_.clear();
img_relinquished_.clear();
tex_relinquished_.clear();
}
ImageCache::Ref::Ref(ImageCache *cache) :
buffer_type_(kInvalidBuf),
cache_(cache),
buffer_(-1),
width_(-1),
height_(-1)
{
}
ImageCache::Ref::~Ref()
{
Relinquish();
}
void *ImageCache::Ref::BufferInternal()
{
// If we don't have a buffer yet, request one
if (buffer_ == -1) {
Request();
}
// If we didn't receive one, return null
if (buffer_ == -1) {
return nullptr;
}
// Otherwise, return the buffer we received
return cache_->Buffer(buffer_, buffer_type_);
}
void ImageCache::Ref::Relinquish()
{
if (buffer_ == -1) {
return;
}
cache_->RelinquishBuffer(buffer_, buffer_type_);
buffer_ = -1;
}
void ImageCache::Ref::Request()
{
// Check if we already have a buffer, in which case we don't need to request a new one
if (buffer_ != -1) {
return;
}
// Check if we have a valid buffer type to request
if (buffer_type_ == kInvalidBuf) {
qWarning() << "Tried to request an invalid buffer type";
return;
}
buffer_ = cache_->RequestBuffer(this, buffer_type_, width_, height_);
}
ImageCache::ImgRef::ImgRef(ImageCache *cache) :
Ref(cache)
{
buffer_type_ = kMemBuf;
}
void ImageCache::ImgRef::SetSize(int w, int h)
{
width_ = w;
height_ = h;
Relinquish();
}
MemoryBuffer *ImageCache::ImgRef::buffer()
{
return static_cast<MemoryBuffer*>(BufferInternal());
}
ImageCache::TexRef::TexRef(ImageCache *cache) :
Ref(cache)
{
buffer_type_ = kTexBuf;
}
FramebufferObject *ImageCache::TexRef::buffer()
{
return static_cast<FramebufferObject*>(BufferInternal());
}
+91
View File
@@ -0,0 +1,91 @@
#ifndef MEMORYCACHE_H
#define MEMORYCACHE_H
#include <QList>
#include <QMutex>
#include "framebufferobject.h"
#include "memorybuffer.h"
class ImageCache
{
public:
enum BufferType {
kInvalidBuf,
kMemBuf, // RAM (CPU) buffer
kTexBuf // VRAM (GPU) buffer
};
class Ref {
public:
Ref(ImageCache* cache);
~Ref();
void Relinquish();
protected:
void* BufferInternal();
BufferType buffer_type_;
int width_;
int height_;
private:
void Request();
ImageCache* cache_;
int buffer_;
};
class ImgRef : public Ref {
public:
ImgRef(ImageCache* cache);
void SetSize(int w, int h);
MemoryBuffer* buffer();
};
class TexRef : public Ref {
public:
TexRef(ImageCache* cache);
FramebufferObject* buffer();
};
ImageCache();
~ImageCache();
void SetParameters(QOpenGLContext* ctx, int width, int height);
private:
int RequestBuffer(Ref *r, const BufferType& type, int width, int height);
int RequestBufferInternal(Ref *r, const BufferType& type, int width, int height);
void RelinquishBuffer(int index, const BufferType& type);
void *Buffer(int index, const BufferType &type);
bool OutOfMemory();
void Clear();
QList<MemoryBuffer> img_buffers_;
QList<Ref*> img_refs_;
QList<time_t> img_access_times_;
QList<int> img_relinquished_;
QList<FramebufferObject> tex_buffers_;
QList<Ref*> tex_refs_;
QList<time_t> tex_access_times_;
QList<int> tex_relinquished_;
QOpenGLContext* ctx_;
int width_;
int height_;
QMutex buffer_array_mutex_;
};
#endif // MEMORYCACHE_H
+43
View File
@@ -0,0 +1,43 @@
#include "memorybuffer.h"
#include <QDebug>
#include "decoders/pixelformatconverter.h"
MemoryBuffer::MemoryBuffer()
{
}
void MemoryBuffer::Create(int width, int height, const olive::PixelFormat &format)
{
width_ = width;
height_ = height;
format_ = format;
data_.resize(olive::pix_fmt_conv->GetBufferSize(format, width, height));
}
const int &MemoryBuffer::width() const
{
return width_;
}
const int &MemoryBuffer::height() const
{
return height_;
}
const olive::PixelFormat &MemoryBuffer::format() const
{
return format_;
}
uint8_t *MemoryBuffer::data()
{
return data_.data();
}
const uint8_t *MemoryBuffer::const_data() const
{
return data_.constData();
}
+28
View File
@@ -0,0 +1,28 @@
#ifndef MEMORYBUFFER_H
#define MEMORYBUFFER_H
#include <QVector>
#include "pixelformats.h"
class MemoryBuffer
{
public:
MemoryBuffer();
void Create(int width, int height, const olive::PixelFormat& format);
const int& width() const;
const int& height() const;
const olive::PixelFormat& format() const;
uint8_t* data();
const uint8_t* const_data() const;
private:
QVector<uint8_t> data_;
int width_;
int height_;
olive::PixelFormat format_;
};
#endif // MEMORYBUFFER_H
-182
View File
@@ -1,182 +0,0 @@
#include "memorycache.h"
#include <QDebug>
MemoryCache::MemoryCache() :
ctx_(nullptr),
width_(0),
height_(0)
{
}
MemoryCache::~MemoryCache()
{
buffer_array_mutex_.lock();
Clear();
buffer_array_mutex_.unlock();
}
void MemoryCache::SetParameters(QOpenGLContext *ctx, int width, int height)
{
buffer_array_mutex_.lock();
ctx_ = ctx;
if (ctx_ != nullptr) {
Q_ASSERT(width > 0 && height > 0);
width_ = width;
height_ = height;
}
Clear();
buffer_array_mutex_.unlock();
}
int MemoryCache::RequestBuffer(Reference* r)
{
if (ctx_ == nullptr) {
qWarning() << "A memcache request was made with an invalid context";
return -1;
}
if (width_ == 0 || height_ == 0) {
qWarning() << "A memcache request was made with an invalid size [" << width_ << "," << height_ << "]";
return -1;
}
buffer_array_mutex_.lock();
int buffer = RequestBufferInternal(r);
buffer_array_mutex_.unlock();
return buffer;
}
int MemoryCache::RequestBufferInternal(MemoryCache::Reference *r)
{
// Try to return a relinquished buffer
if (!relinquished_buffers_.isEmpty()) {
int buf_index = relinquished_buffers_.takeFirst();
refs_.replace(buf_index, r);
return buf_index;
}
// If no buffer was available, we may have to create a new one
// Check if we have enough memory (according to user-defined limits in the Config), if we don't, try to relinquish an
// old buffer and return that.
if (OutOfMemory()) {
int least_recent_access = 0;
// Loop through buffers for the oldest accessed buffer
for (int i=1;i<access_times_.size();i++) {
if (access_times_.at(i) < access_times_.at(least_recent_access)
&& refs_.at(i) != nullptr) { // ensure this buffer has not been relinquished
least_recent_access = i;
}
}
// Relinquish this buffer
refs_.at(least_recent_access)->Relinquish();
refs_.replace(least_recent_access, r);
return least_recent_access;
}
// Otherwise, just generate a new buffer
buffers_.append(FramebufferObject());
refs_.append(r);
access_times_.append(time(nullptr));
buffers_.last().Create(ctx_, width_, height_);
return buffers_.size() - 1;
}
void MemoryCache::RelinquishBuffer(int index)
{
buffer_array_mutex_.lock();
refs_.replace(index, nullptr);
relinquished_buffers_.append(index);
buffer_array_mutex_.unlock();
}
FramebufferObject* MemoryCache::Buffer(int index)
{
access_times_.replace(index, time(nullptr));
return &buffers_[index];
}
bool MemoryCache::OutOfMemory()
{
// TODO actually check if we have any memory or not
return false;
}
void MemoryCache::Clear()
{
for (int i=0;i<refs_.size();i++) {
refs_.at(i)->Relinquish();
}
buffers_.clear();
refs_.clear();
relinquished_buffers_.clear();
}
MemoryCache::Reference::Reference(MemoryCache *cache) :
cache_(cache),
buffer_(-1)
{
}
MemoryCache::Reference::~Reference()
{
Relinquish();
}
FramebufferObject *MemoryCache::Reference::buffer()
{
// If we don't have a buffer yet, request one
if (buffer_ == -1) {
Request();
}
// If we didn't receive one, return null
if (buffer_ == -1) {
return nullptr;
}
// Otherwise, return the buffer we received
return &cache_->buffers_[buffer_];
}
void MemoryCache::Reference::Relinquish()
{
if (buffer_ == -1) {
return;
}
cache_->RelinquishBuffer(buffer_);
buffer_ = -1;
}
void MemoryCache::Reference::Request()
{
// Check if we already have a buffer, in which case we don't need to request a new one
if (buffer_ != -1) {
return;
}
buffer_ = cache_->RequestBuffer(this);
}
-58
View File
@@ -1,58 +0,0 @@
#ifndef MEMORYCACHE_H
#define MEMORYCACHE_H
#include <QList>
#include <QMutex>
#include "framebufferobject.h"
class MemoryCache
{
public:
class Reference {
public:
Reference(MemoryCache* cache);
~Reference();
FramebufferObject* buffer();
void Relinquish();
private:
void Request();
MemoryCache* cache_;
int buffer_;
};
MemoryCache();
~MemoryCache();
void SetParameters(QOpenGLContext* ctx, int width, int height);
private:
int RequestBuffer(Reference *r);
int RequestBufferInternal(Reference *r);
void RelinquishBuffer(int index);
FramebufferObject *Buffer(int index);
bool OutOfMemory();
void Clear();
QList<FramebufferObject> buffers_;
QList<Reference*> refs_;
QList<time_t> access_times_;
QOpenGLContext* ctx_;
QList<int> relinquished_buffers_;
int width_;
int height_;
QMutex buffer_array_mutex_;
};
#endif // MEMORYCACHE_H