mirror of
https://github.com/brunoherbelin/vimix.git
synced 2025-12-12 10:49:59 +01:00
Graphics Card Memory check before allocating FBO
Improved warning when allocating FrameBuffer. Avoid allocating FrameBuffer when buffering delay in Clone Source if we risk to consume all RAM in graphics card.
This commit is contained in:
@@ -35,7 +35,7 @@ const char* CloneSource::cloning_provenance_label[2] = { "Original texture", "Po
|
|||||||
|
|
||||||
|
|
||||||
CloneSource::CloneSource(Source *origin, uint64_t id) : Source(id), origin_(origin), cloningsurface_(nullptr),
|
CloneSource::CloneSource(Source *origin, uint64_t id) : Source(id), origin_(origin), cloningsurface_(nullptr),
|
||||||
to_delete_(nullptr), delay_(0.0), paused_(false), provenance_(CLONE_TEXTURE)
|
garbage_image_(nullptr), delay_(0.0), paused_(false), provenance_(CLONE_TEXTURE)
|
||||||
{
|
{
|
||||||
// initial name copies the origin name: diplucates are namanged in session
|
// initial name copies the origin name: diplucates are namanged in session
|
||||||
name_ = origin->name();
|
name_ = origin->name();
|
||||||
@@ -152,18 +152,19 @@ void CloneSource::update(float dt)
|
|||||||
if (!paused_ && cloningsurface_ != nullptr) {
|
if (!paused_ && cloningsurface_ != nullptr) {
|
||||||
|
|
||||||
// if temporary FBO was pending to be deleted, delete it now
|
// if temporary FBO was pending to be deleted, delete it now
|
||||||
if (to_delete_ != nullptr) {
|
if (garbage_image_ != nullptr) {
|
||||||
delete to_delete_;
|
delete garbage_image_;
|
||||||
to_delete_ = nullptr;
|
garbage_image_ = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// What time is it?
|
// What time is it?
|
||||||
double now = g_timer_elapsed (timer_, NULL);
|
double now = g_timer_elapsed (timer_, NULL);
|
||||||
|
|
||||||
// is the total buffer of images longer than delay ?
|
// is the total buffer of images longer than delay ?
|
||||||
if ( !images_.empty() && now - elapsed_.front() > delay_ ) {
|
if ( !images_.empty() && now - elapsed_.front() > delay_ )
|
||||||
|
{
|
||||||
// remember FBO to be reused if needed (see below) or deleted later
|
// remember FBO to be reused if needed (see below) or deleted later
|
||||||
to_delete_ = images_.front();
|
garbage_image_ = images_.front();
|
||||||
// remove element from queue (front)
|
// remove element from queue (front)
|
||||||
images_.pop();
|
images_.pop();
|
||||||
elapsed_.pop();
|
elapsed_.pop();
|
||||||
@@ -171,16 +172,24 @@ void CloneSource::update(float dt)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// add image to queue to accumulate buffer images until delay reached
|
// add image to queue to accumulate buffer images until delay reached
|
||||||
if ( images_.empty() || now - elapsed_.front() < delay_ + (dt * 0.001) ) {
|
if ( images_.empty() || now - elapsed_.front() < delay_ + (dt * 0.001) )
|
||||||
// create a FBO if none can be reused (from above)
|
{
|
||||||
if (to_delete_ == nullptr)
|
// create a FBO if none can be reused (from above) and test for RAM in GPU
|
||||||
to_delete_ = new FrameBuffer( origin_->frame()->resolution(), origin_->frame()->use_alpha() );
|
if (garbage_image_ == nullptr && ( images_.empty() || FrameBuffer::shouldHaveEnoughMemory(origin_->frame()->resolution(), origin_->frame()->use_alpha()) ) )
|
||||||
// add element to queue (back)
|
garbage_image_ = new FrameBuffer( origin_->frame()->resolution(), origin_->frame()->use_alpha() );
|
||||||
images_.push( to_delete_ );
|
// no image available
|
||||||
elapsed_.push( now );
|
if (garbage_image_ != nullptr) {
|
||||||
timestamps_.push( origin_->playtime() );
|
// add element to queue (back)
|
||||||
// to_delete_ FBO is now used, should not be deleted
|
images_.push( garbage_image_ );
|
||||||
to_delete_ = nullptr;
|
elapsed_.push( now );
|
||||||
|
timestamps_.push( origin_->playtime() );
|
||||||
|
// garbage_image_ FBO is now used, it should not be deleted
|
||||||
|
garbage_image_ = nullptr;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
delay_ = now - elapsed_.front() - (dt * 0.001);
|
||||||
|
Log::Warning("Cannot satisfy delay for Clone %s: not enough RAM in graphics card.", name_.c_str());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// CLONE_RENDER : blit rendered framebuffer in the newest image (back)
|
// CLONE_RENDER : blit rendered framebuffer in the newest image (back)
|
||||||
@@ -232,16 +241,17 @@ bool CloneSource::playable () const
|
|||||||
void CloneSource::replay()
|
void CloneSource::replay()
|
||||||
{
|
{
|
||||||
// clear to_delete_ FBO if pending
|
// clear to_delete_ FBO if pending
|
||||||
if (to_delete_ != nullptr) {
|
if (garbage_image_ != nullptr) {
|
||||||
delete to_delete_;
|
g_printerr(" REPLAY delete garbage %d \n", garbage_image_->opengl_id());
|
||||||
to_delete_ = nullptr;
|
delete garbage_image_;
|
||||||
|
garbage_image_ = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// remove all images except the one in the back (newest)
|
// remove all images except the one in the back (newest)
|
||||||
while (images_.size() > 1) {
|
while (images_.size() > 1) {
|
||||||
// do not delete immediately the (oldest) front image (the FBO is currently displayed)
|
// do not delete immediately the (oldest) front image (the FBO is currently displayed)
|
||||||
if (to_delete_ == nullptr)
|
if (garbage_image_ == nullptr)
|
||||||
to_delete_ = images_.front();
|
garbage_image_ = images_.front();
|
||||||
// delete other FBO (unused)
|
// delete other FBO (unused)
|
||||||
else if (images_.front() != nullptr)
|
else if (images_.front() != nullptr)
|
||||||
delete images_.front();
|
delete images_.front();
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ protected:
|
|||||||
// cloning & queue of past frames
|
// cloning & queue of past frames
|
||||||
std::queue<FrameBuffer *> images_;
|
std::queue<FrameBuffer *> images_;
|
||||||
Surface *cloningsurface_;
|
Surface *cloningsurface_;
|
||||||
FrameBuffer *to_delete_;
|
FrameBuffer *garbage_image_;
|
||||||
|
|
||||||
// time management
|
// time management
|
||||||
GTimer *timer_;
|
GTimer *timer_;
|
||||||
|
|||||||
205
FrameBuffer.cpp
205
FrameBuffer.cpp
@@ -32,7 +32,7 @@
|
|||||||
#include <stb_image_write.h>
|
#include <stb_image_write.h>
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
//#define FRAMEBUFFER_DEBUG
|
#define FRAMEBUFFER_DEBUG
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define GL_GPU_MEM_INFO_TOTAL_AVAILABLE_MEM_NVX 0x9048
|
#define GL_GPU_MEM_INFO_TOTAL_AVAILABLE_MEM_NVX 0x9048
|
||||||
@@ -140,7 +140,7 @@ void FrameBuffer::init()
|
|||||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureid_, 0);
|
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureid_, 0);
|
||||||
|
|
||||||
#ifdef FRAMEBUFFER_DEBUG
|
#ifdef FRAMEBUFFER_DEBUG
|
||||||
g_printerr("New FBO %d Multi Sampling ", framebufferid_);
|
g_printerr("New FBO %d Multi Sampling\n", framebufferid_);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -149,7 +149,7 @@ void FrameBuffer::init()
|
|||||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureid_, 0);
|
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureid_, 0);
|
||||||
|
|
||||||
#ifdef FRAMEBUFFER_DEBUG
|
#ifdef FRAMEBUFFER_DEBUG
|
||||||
g_printerr("New FBO %d Single Sampling ", framebufferid_);
|
g_printerr("New FBO %d Single Sampling\n", framebufferid_);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -171,8 +171,8 @@ FrameBuffer::~FrameBuffer()
|
|||||||
glDeleteTextures(1, &intermediate_textureid_);
|
glDeleteTextures(1, &intermediate_textureid_);
|
||||||
|
|
||||||
#ifdef FRAMEBUFFER_DEBUG
|
#ifdef FRAMEBUFFER_DEBUG
|
||||||
GLint framebufferMemoryInKB = ( width() * height() * 5 ) / 1024;
|
GLint framebufferMemoryInKB = ( width() * height() * (use_alpha_?4:3) ) / 1024;
|
||||||
g_printerr("Framebuffer deleted %d x %d, %d kB freed\n", width(), height(), framebufferMemoryInKB);
|
g_printerr("Framebuffer deleted %d x %d, ~%d kB freed\n", width(), height(), framebufferMemoryInKB);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -313,102 +313,129 @@ void FrameBuffer::checkFramebufferStatus()
|
|||||||
{
|
{
|
||||||
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
||||||
switch (status){
|
switch (status){
|
||||||
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
|
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
|
||||||
Log::Warning("GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT is returned if any of the framebuffer attachment points are framebuffer incomplete.");
|
Log::Warning("GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT is returned if any of the framebuffer attachment points are framebuffer incomplete.");
|
||||||
break;
|
break;
|
||||||
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
|
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
|
||||||
Log::Warning("GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT is returned if the framebuffer does not have at least one image attached to it.");
|
Log::Warning("GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT is returned if the framebuffer does not have at least one image attached to it.");
|
||||||
break;
|
break;
|
||||||
case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER:
|
case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER:
|
||||||
Log::Warning("GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER is returned if the value of GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE is GL_NONE for any color "
|
Log::Warning("GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER is returned if the value of GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE is GL_NONE for any color "
|
||||||
"attachment point(s) named by GL_DRAWBUFFERi.");
|
"attachment point(s) named by GL_DRAWBUFFERi.");
|
||||||
break;
|
break;
|
||||||
case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER:
|
case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER:
|
||||||
Log::Warning("GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER is returned if GL_READ_BUFFER is not GL_NONE and the value of "
|
Log::Warning("GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER is returned if GL_READ_BUFFER is not GL_NONE and the value of "
|
||||||
"GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE is GL_NONE for the color attachment point named by GL_READ_BUFFER.");
|
"GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE is GL_NONE for the color attachment point named by GL_READ_BUFFER.");
|
||||||
break;
|
break;
|
||||||
case GL_FRAMEBUFFER_UNSUPPORTED:
|
case GL_FRAMEBUFFER_UNSUPPORTED:
|
||||||
Log::Warning("GL_FRAMEBUFFER_UNSUPPORTED is returned if the combination of internal formats of the attached images violates an "
|
Log::Warning("GL_FRAMEBUFFER_UNSUPPORTED is returned if the combination of internal formats of the attached images violates an "
|
||||||
"implementation-dependent set of restrictions.");
|
"implementation-dependent set of restrictions.");
|
||||||
break;
|
break;
|
||||||
case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE:
|
case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE:
|
||||||
Log::Warning("GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE is returned if the value of GL_RENDERBUFFER_SAMPLES is not the same for all attached renderbuffers; "
|
Log::Warning("GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE is returned if the value of GL_RENDERBUFFER_SAMPLES is not the same for all attached renderbuffers; "
|
||||||
"if the value of GL_TEXTURE_SAMPLES is the not same for all attached textures; or, if the attached images are a mix of renderbuffers and textures, the value of "
|
"if the value of GL_TEXTURE_SAMPLES is the not same for all attached textures; or, if the attached images are a mix of renderbuffers and textures, the value of "
|
||||||
"GL_RENDERBUFFER_SAMPLES does not match the value of GL_TEXTURE_SAMPLES.\nGL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE is also returned if the value of "
|
"GL_RENDERBUFFER_SAMPLES does not match the value of GL_TEXTURE_SAMPLES.\nGL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE is also returned if the value of "
|
||||||
"GL_TEXTURE_FIXED_SAMPLE_LOCATIONS is not the same for all attached textures; or, if the attached images are a mix of renderbuffers and textures, "
|
"GL_TEXTURE_FIXED_SAMPLE_LOCATIONS is not the same for all attached textures; or, if the attached images are a mix of renderbuffers and textures, "
|
||||||
"the value of GL_TEXTURE_FIXED_SAMPLE_LOCATIONS is not GL_TRUE for all attached textures.");
|
"the value of GL_TEXTURE_FIXED_SAMPLE_LOCATIONS is not GL_TRUE for all attached textures.");
|
||||||
break;
|
break;
|
||||||
case GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS:
|
case GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS:
|
||||||
Log::Warning("GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS is returned if any framebuffer attachment is layered, and any populated attachment is not layered,"
|
Log::Warning("GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS is returned if any framebuffer attachment is layered, and any populated attachment is not layered,"
|
||||||
" or if all populated color attachments are not from textures of the same target.");
|
" or if all populated color attachments are not from textures of the same target.");
|
||||||
break;
|
break;
|
||||||
case GL_FRAMEBUFFER_UNDEFINED:
|
case GL_FRAMEBUFFER_UNDEFINED:
|
||||||
Log::Warning(" GL_FRAMEBUFFER_UNDEFINED is returned if target is the default framebuffer, but the default framebuffer does not exist.");
|
Log::Warning(" GL_FRAMEBUFFER_UNDEFINED is returned if target is the default framebuffer, but the default framebuffer does not exist.");
|
||||||
break;
|
break;
|
||||||
case GL_FRAMEBUFFER_COMPLETE:
|
case GL_FRAMEBUFFER_COMPLETE:
|
||||||
|
|
||||||
{
|
{
|
||||||
static int meminfomode = -1;
|
|
||||||
// first time check which way to get memory info
|
|
||||||
if (meminfomode<0) {
|
|
||||||
meminfomode = 0;
|
|
||||||
GLint numExtensions = 0;
|
|
||||||
glGetIntegerv( GL_NUM_EXTENSIONS, &numExtensions );
|
|
||||||
for (int i = 0; i < numExtensions; ++i){
|
|
||||||
|
|
||||||
const GLubyte *ccc = glGetStringi(GL_EXTENSIONS, i);
|
// approximation of RAM needed for this FBO
|
||||||
if ( strcmp( (const char*)ccc, "GL_NVX_gpu_memory_info") == 0 ){
|
GLint framebufferMemoryInKB = ( width() * height() * (use_alpha_?4:3) * (use_multi_sampling_?2:1) ) / 1024;
|
||||||
meminfomode = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else if ( strcmp( (const char*)ccc, "GL_ATI_meminfo") == 0 ){
|
|
||||||
meminfomode = 2;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
// test available memory if created buffer is big (more than 8MB)
|
||||||
|
if ( framebufferMemoryInKB > 8000 ) {
|
||||||
|
|
||||||
GLint framebufferMemoryInKB = ( width() * height() * 5 ) / 1024;
|
// Obtain RAM usage in GPU (if possible)
|
||||||
|
glm::ivec2 RAM = getGPUMemoryInformation();
|
||||||
|
|
||||||
// NVIDIA
|
// bad case: not enough RAM, we should warn the user
|
||||||
if (meminfomode == 1) {
|
if ( RAM.x < framebufferMemoryInKB * 3 ) {
|
||||||
static GLint nTotalMemoryInKB = -1;
|
Log::Warning("Critical allocation of frame buffer: only %d kB RAM remaining in graphics card.", RAM.x );
|
||||||
if (nTotalMemoryInKB<0)
|
if (RAM.y < INT_MAX)
|
||||||
glGetIntegerv( GL_GPU_MEM_INFO_TOTAL_AVAILABLE_MEM_NVX, &nTotalMemoryInKB );
|
Log::Warning("Only %.1f %% of %d kB available.", 100.f*float(RAM.x)/float(RAM.y), RAM.y);
|
||||||
|
|
||||||
GLint nCurAvailMemoryInKB = 0;
|
|
||||||
glGetIntegerv( GL_GPU_MEM_INFO_CURRENT_AVAILABLE_MEM_NVX, &nCurAvailMemoryInKB );
|
|
||||||
|
|
||||||
if ( nCurAvailMemoryInKB < framebufferMemoryInKB )
|
|
||||||
Log::Warning("Cannot allocate frame buffer: only %d kB GPU RAM remaining on the %d kB available (%d %%).",
|
|
||||||
nCurAvailMemoryInKB, nTotalMemoryInKB, int(float(nCurAvailMemoryInKB) / float(nTotalMemoryInKB) * 100.f ) );
|
|
||||||
#ifdef FRAMEBUFFER_DEBUG
|
|
||||||
else
|
|
||||||
g_printerr("Framebuffer created %d x %d, %d kB allocated (%d kB remaining on %d kB)\n", width(), height(), framebufferMemoryInKB, nCurAvailMemoryInKB, nTotalMemoryInKB);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
// ATI
|
|
||||||
else if (meminfomode == 2) {
|
|
||||||
|
|
||||||
GLint nCurAvailMemoryInKB = 0;
|
|
||||||
glGetIntegerv( GL_TEXTURE_FREE_MEMORY_ATI, &nCurAvailMemoryInKB );
|
|
||||||
|
|
||||||
if ( nCurAvailMemoryInKB < framebufferMemoryInKB )
|
|
||||||
Log::Warning("Cannot allocate frame buffer: only %d kB GPU RAM remaining.", nCurAvailMemoryInKB );
|
|
||||||
#ifdef FRAMEBUFFER_DEBUG
|
|
||||||
else
|
|
||||||
g_printerr("Framebuffer created %d x %d, %d kB allocated (%d kB remaining)\n", width(), height(), framebufferMemoryInKB, nCurAvailMemoryInKB);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
#ifdef FRAMEBUFFER_DEBUG
|
#ifdef FRAMEBUFFER_DEBUG
|
||||||
else
|
else {
|
||||||
g_printerr("Framebuffer created %d x %d, %d kB allocated\n", width(), height(), framebufferMemoryInKB);
|
// normal case: enough RAM (or unknown) for this FBO
|
||||||
|
g_printerr("Framebuffer allocated %d x %d, ~%d kB", width(), height(), framebufferMemoryInKB);
|
||||||
|
if (RAM.x < INT_MAX)
|
||||||
|
g_printerr(" (%d kB remaining)", RAM.x);
|
||||||
|
g_printerr("\n");
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// RAM usage in GPU
|
||||||
|
// returns { CurAvailMemoryInKB, TotalMemoryInKB }
|
||||||
|
// MAX values means the info in not available
|
||||||
|
glm::ivec2 FrameBuffer::getGPUMemoryInformation()
|
||||||
|
{
|
||||||
|
glm::ivec2 ret(INT_MAX, INT_MAX);
|
||||||
|
|
||||||
|
// Detect method to get info
|
||||||
|
static int meminfomode = -1;
|
||||||
|
if (meminfomode<0) {
|
||||||
|
// initialized
|
||||||
|
meminfomode = 0;
|
||||||
|
GLint numExtensions = 0;
|
||||||
|
glGetIntegerv( GL_NUM_EXTENSIONS, &numExtensions );
|
||||||
|
for (int i = 0; i < numExtensions; ++i){
|
||||||
|
const GLubyte *ccc = glGetStringi(GL_EXTENSIONS, i);
|
||||||
|
// NVIDIA extension available
|
||||||
|
if ( strcmp( (const char*)ccc, "GL_NVX_gpu_memory_info") == 0 ){
|
||||||
|
meminfomode = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// ATI extension available
|
||||||
|
else if ( strcmp( (const char*)ccc, "GL_ATI_meminfo") == 0 ){
|
||||||
|
meminfomode = 2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// NVIDIA
|
||||||
|
if (meminfomode == 1) {
|
||||||
|
static GLint nTotalMemoryInKB = -1;
|
||||||
|
if (nTotalMemoryInKB<0)
|
||||||
|
glGetIntegerv( GL_GPU_MEM_INFO_TOTAL_AVAILABLE_MEM_NVX, &nTotalMemoryInKB );
|
||||||
|
ret.y = nTotalMemoryInKB;
|
||||||
|
|
||||||
|
glGetIntegerv( GL_GPU_MEM_INFO_CURRENT_AVAILABLE_MEM_NVX, &ret.x );
|
||||||
|
}
|
||||||
|
// ATI
|
||||||
|
else if (meminfomode == 2) {
|
||||||
|
glGetIntegerv( GL_TEXTURE_FREE_MEMORY_ATI, &ret.x );
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool FrameBuffer::shouldHaveEnoughMemory(glm::vec3 resolution, bool useAlpha, bool multiSampling)
|
||||||
|
{
|
||||||
|
glm::ivec2 RAM = getGPUMemoryInformation();
|
||||||
|
|
||||||
|
// approximation of RAM needed for such FBO
|
||||||
|
GLint framebufferMemoryInKB = ( resolution.x * resolution.x * (useAlpha?4:3) * (multiSampling?2:1) ) / 1024;
|
||||||
|
|
||||||
|
return ( RAM.x > framebufferMemoryInKB * 3 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -44,8 +44,9 @@ public:
|
|||||||
static float resolution_height[5];
|
static float resolution_height[5];
|
||||||
static glm::vec3 getResolutionFromParameters(int ar, int h);
|
static glm::vec3 getResolutionFromParameters(int ar, int h);
|
||||||
static glm::ivec2 getParametersFromResolution(glm::vec3 res);
|
static glm::ivec2 getParametersFromResolution(glm::vec3 res);
|
||||||
// unbind any framebuffer object
|
// memory management
|
||||||
static void release();
|
static glm::ivec2 getGPUMemoryInformation();
|
||||||
|
static bool shouldHaveEnoughMemory(glm::vec3 resolution, bool useAlpha = false, bool multiSampling = false);
|
||||||
|
|
||||||
FrameBuffer(glm::vec3 resolution, bool useAlpha = false, bool multiSampling = false);
|
FrameBuffer(glm::vec3 resolution, bool useAlpha = false, bool multiSampling = false);
|
||||||
FrameBuffer(uint width, uint height, bool useAlpha = false, bool multiSampling = false);
|
FrameBuffer(uint width, uint height, bool useAlpha = false, bool multiSampling = false);
|
||||||
@@ -56,6 +57,8 @@ public:
|
|||||||
void begin(bool clear = true);
|
void begin(bool clear = true);
|
||||||
// pop attrib and unbind to end draw
|
// pop attrib and unbind to end draw
|
||||||
void end();
|
void end();
|
||||||
|
// unbind (any) framebuffer object
|
||||||
|
static void release();
|
||||||
// blit copy to another, returns true on success
|
// blit copy to another, returns true on success
|
||||||
bool blit(FrameBuffer *destination);
|
bool blit(FrameBuffer *destination);
|
||||||
// bind the FrameBuffer in READ and perform glReadPixels
|
// bind the FrameBuffer in READ and perform glReadPixels
|
||||||
@@ -101,7 +104,6 @@ private:
|
|||||||
uint textureid_, intermediate_textureid_;
|
uint textureid_, intermediate_textureid_;
|
||||||
uint framebufferid_, intermediate_framebufferid_;
|
uint framebufferid_, intermediate_framebufferid_;
|
||||||
bool use_alpha_, use_multi_sampling_;
|
bool use_alpha_, use_multi_sampling_;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user