render implement thread, wrap GL commands into tasks
This commit is contained in:
249
src/rtt.cpp
249
src/rtt.cpp
@@ -2,6 +2,7 @@
|
||||
#include "log.h"
|
||||
#include "rtt.h"
|
||||
#include "util.h"
|
||||
#include "app.h"
|
||||
|
||||
RTT::RTT()
|
||||
{
|
||||
@@ -38,19 +39,22 @@ void RTT::resize(int width, int height)
|
||||
{
|
||||
RTT new_rtt;
|
||||
|
||||
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &oldDFboID);
|
||||
glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &oldRFboID);
|
||||
App::I.render_task([&]
|
||||
{
|
||||
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &oldDFboID);
|
||||
glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &oldRFboID);
|
||||
|
||||
new_rtt.create(width, height, -1, int_fmt, rboID != 0);
|
||||
new_rtt.create(width, height, -1, int_fmt, rboID != 0);
|
||||
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, new_rtt.fboID);
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, fboID);
|
||||
glBlitFramebuffer(0, 0, w, h, 0, 0, new_rtt.w, new_rtt.h, GL_COLOR_BUFFER_BIT, GL_LINEAR);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, new_rtt.fboID);
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, fboID);
|
||||
glBlitFramebuffer(0, 0, w, h, 0, 0, new_rtt.w, new_rtt.h, GL_COLOR_BUFFER_BIT, GL_LINEAR);
|
||||
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, oldDFboID);
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, oldRFboID);
|
||||
|
||||
destroy();
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, oldDFboID);
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, oldRFboID);
|
||||
|
||||
destroy();
|
||||
});
|
||||
|
||||
oldRFboID = 0;
|
||||
oldDFboID = 0;
|
||||
@@ -64,22 +68,25 @@ void RTT::resize(int width, int height)
|
||||
|
||||
void RTT::destroy()
|
||||
{
|
||||
if (rboID)
|
||||
App::I.render_task_async([rboID=rboID, texID=texID, fboID=fboID]
|
||||
{
|
||||
glDeleteRenderbuffers(1, &rboID);
|
||||
}
|
||||
if (texID)
|
||||
{
|
||||
unbindTexture();
|
||||
glDeleteTextures(1, &texID);
|
||||
//LOG("TEX rtt destroy %d", texID)
|
||||
}
|
||||
if (fboID)
|
||||
{
|
||||
unbindFramebuffer();
|
||||
glDeleteFramebuffers(1, &fboID);
|
||||
//LOG("RTT DESTROY %d", fboID);
|
||||
}
|
||||
if (rboID)
|
||||
{
|
||||
glDeleteRenderbuffers(1, &rboID);
|
||||
}
|
||||
if (texID)
|
||||
{
|
||||
//unbindTexture();
|
||||
glDeleteTextures(1, &texID);
|
||||
//LOG("TEX rtt destroy %d", texID)
|
||||
}
|
||||
if (fboID)
|
||||
{
|
||||
//unbindFramebuffer();
|
||||
glDeleteFramebuffers(1, &fboID);
|
||||
//LOG("RTT DESTROY %d", fboID);
|
||||
}
|
||||
});
|
||||
texID = 0;
|
||||
fboID = 0;
|
||||
rboID = 0;
|
||||
@@ -89,101 +96,109 @@ void RTT::destroy()
|
||||
|
||||
void RTT::copy(const RTT & source)
|
||||
{
|
||||
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &oldDFboID);
|
||||
glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &oldRFboID);
|
||||
App::I.render_task([&]
|
||||
{
|
||||
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &oldDFboID);
|
||||
glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &oldRFboID);
|
||||
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fboID);
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, source.fboID);
|
||||
glBlitFramebuffer(0, 0, source.w, source.h, 0, 0, w, h, GL_COLOR_BUFFER_BIT, GL_LINEAR);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fboID);
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, source.fboID);
|
||||
glBlitFramebuffer(0, 0, source.w, source.h, 0, 0, w, h, GL_COLOR_BUFFER_BIT, GL_LINEAR);
|
||||
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, oldDFboID);
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, oldRFboID);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, oldDFboID);
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, oldRFboID);
|
||||
});
|
||||
}
|
||||
|
||||
bool RTT::create(int width, int height, int tex/* = -1*/, GLint internal_format, bool depth_buffer /*= false*/)
|
||||
{
|
||||
// Destroy any previously created object
|
||||
destroy();
|
||||
|
||||
w = width;
|
||||
h = height;
|
||||
int_fmt = internal_format;
|
||||
|
||||
if (tex == -1)
|
||||
GLenum status = 0;
|
||||
App::I.render_task([&]
|
||||
{
|
||||
glGenTextures(1, &texID);
|
||||
//LOG("TEX rtt create %d", texID);
|
||||
}
|
||||
else
|
||||
{
|
||||
texID = tex;
|
||||
}
|
||||
// Destroy any previously created object
|
||||
destroy();
|
||||
|
||||
auto ifmt = GL_UNSIGNED_BYTE;
|
||||
if (internal_format == GL_RGBA32F) ifmt = GL_FLOAT;
|
||||
if (internal_format == GL_RGBA16F) ifmt = GL_HALF_FLOAT;
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, texID);
|
||||
if (tex == -1)
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, internal_format, width, height, 0, GL_RGBA, ifmt, 0);
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
w = width;
|
||||
h = height;
|
||||
int_fmt = internal_format;
|
||||
|
||||
// Create a renderbuffer object to store depth info
|
||||
if (depth_buffer)
|
||||
{
|
||||
glGenRenderbuffers(1, &rboID);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, rboID);
|
||||
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, width, height);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, 0);
|
||||
}
|
||||
|
||||
GLint oldFboID;
|
||||
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &oldFboID);
|
||||
|
||||
// Create a framebuffer object
|
||||
glGenFramebuffers(1, &fboID);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fboID);
|
||||
//LOG("RTT CREATE %d - tex %d", fboID, texID);
|
||||
|
||||
// Attach the texture to FBO color attachment point
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texID, 0);
|
||||
if (depth_buffer)
|
||||
{
|
||||
// Attach the renderbuffer to depth attachment point
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rboID);
|
||||
}
|
||||
|
||||
auto err2str = [](GLenum err) {
|
||||
switch (err)
|
||||
if (tex == -1)
|
||||
{
|
||||
case GL_FRAMEBUFFER_UNDEFINED: return "GL_FRAMEBUFFER_UNDEFINED";
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: return "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT";
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: return "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT";
|
||||
case GL_FRAMEBUFFER_UNSUPPORTED: return "GL_FRAMEBUFFER_UNSUPPORTED";
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE: return "GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE";
|
||||
default: return "UNKNOWN";
|
||||
glGenTextures(1, &texID);
|
||||
//LOG("TEX rtt create %d", texID);
|
||||
}
|
||||
else
|
||||
{
|
||||
texID = tex;
|
||||
}
|
||||
};
|
||||
|
||||
// Check FBO status
|
||||
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
||||
if (status != GL_FRAMEBUFFER_COMPLETE)
|
||||
LOG("RTT::create failed because: %s", err2str(status));
|
||||
auto ifmt = GL_UNSIGNED_BYTE;
|
||||
if (internal_format == GL_RGBA32F) ifmt = GL_FLOAT;
|
||||
if (internal_format == GL_RGBA16F) ifmt = GL_HALF_FLOAT;
|
||||
|
||||
// Switch back to window-system-provided framebuffer
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, oldFboID);
|
||||
oldRFboID = 0;
|
||||
oldDFboID = 0;
|
||||
glBindTexture(GL_TEXTURE_2D, texID);
|
||||
if (tex == -1)
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, internal_format, width, height, 0, GL_RGBA, ifmt, 0);
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
// Create a renderbuffer object to store depth info
|
||||
if (depth_buffer)
|
||||
{
|
||||
glGenRenderbuffers(1, &rboID);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, rboID);
|
||||
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, width, height);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, 0);
|
||||
}
|
||||
|
||||
GLint oldFboID;
|
||||
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &oldFboID);
|
||||
|
||||
// Create a framebuffer object
|
||||
glGenFramebuffers(1, &fboID);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fboID);
|
||||
//LOG("RTT CREATE %d - tex %d", fboID, texID);
|
||||
|
||||
// Attach the texture to FBO color attachment point
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texID, 0);
|
||||
if (depth_buffer)
|
||||
{
|
||||
// Attach the renderbuffer to depth attachment point
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rboID);
|
||||
}
|
||||
|
||||
auto err2str = [](GLenum err) {
|
||||
switch (err)
|
||||
{
|
||||
case GL_FRAMEBUFFER_UNDEFINED: return "GL_FRAMEBUFFER_UNDEFINED";
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: return "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT";
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: return "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT";
|
||||
case GL_FRAMEBUFFER_UNSUPPORTED: return "GL_FRAMEBUFFER_UNSUPPORTED";
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE: return "GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE";
|
||||
default: return "UNKNOWN";
|
||||
}
|
||||
};
|
||||
|
||||
// Check FBO status
|
||||
status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
||||
if (status != GL_FRAMEBUFFER_COMPLETE)
|
||||
LOG("RTT::create failed because: %s", err2str(status));
|
||||
|
||||
// Switch back to window-system-provided framebuffer
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, oldFboID);
|
||||
oldRFboID = 0;
|
||||
oldDFboID = 0;
|
||||
});
|
||||
|
||||
return status == GL_FRAMEBUFFER_COMPLETE;
|
||||
}
|
||||
|
||||
void RTT::bindFramebuffer()
|
||||
{
|
||||
assert(App::I.is_render_thread());
|
||||
#ifdef _DEBUG
|
||||
if (bound)
|
||||
{
|
||||
@@ -193,15 +208,16 @@ void RTT::bindFramebuffer()
|
||||
#endif
|
||||
}
|
||||
#endif // _DEBUG
|
||||
bound = true;
|
||||
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &oldDFboID);
|
||||
glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &oldRFboID);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fboID);
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, fboID);
|
||||
bound = true;
|
||||
}
|
||||
|
||||
void RTT::unbindFramebuffer()
|
||||
{
|
||||
assert(App::I.is_render_thread());
|
||||
if (!bound)
|
||||
return;
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, oldDFboID);
|
||||
@@ -213,6 +229,7 @@ void RTT::unbindFramebuffer()
|
||||
|
||||
void RTT::clear(glm::vec4 color)
|
||||
{
|
||||
assert(App::I.is_render_thread());
|
||||
glClearColor(color.r, color.g, color.b, color.a);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
}
|
||||
@@ -240,11 +257,14 @@ uint8_t* RTT::readTextureData(uint8_t* buffer)
|
||||
{
|
||||
if (!buffer)
|
||||
buffer = createBuffer();
|
||||
GLint old;
|
||||
glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &old);
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, fboID);
|
||||
glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, old);
|
||||
App::I.render_task([&]
|
||||
{
|
||||
GLint old;
|
||||
glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &old);
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, fboID);
|
||||
glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, old);
|
||||
});
|
||||
return buffer;
|
||||
}
|
||||
|
||||
@@ -252,11 +272,14 @@ float* RTT::readTextureDataFloat(float* buffer)
|
||||
{
|
||||
if (!buffer)
|
||||
buffer = createBufferFloat();
|
||||
GLint old;
|
||||
glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &old);
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, fboID);
|
||||
glReadPixels(0, 0, w, h, GL_RGBA, GL_FLOAT, buffer);
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, old);
|
||||
App::I.render_task([&]
|
||||
{
|
||||
GLint old;
|
||||
glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &old);
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, fboID);
|
||||
glReadPixels(0, 0, w, h, GL_RGBA, GL_FLOAT, buffer);
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, old);
|
||||
});
|
||||
return buffer;
|
||||
}
|
||||
|
||||
@@ -272,11 +295,13 @@ float * RTT::createBufferFloat()
|
||||
|
||||
void RTT::bindTexture()
|
||||
{
|
||||
assert(App::I.is_render_thread());
|
||||
glBindTexture(GL_TEXTURE_2D, texID);
|
||||
}
|
||||
|
||||
void RTT::unbindTexture()
|
||||
{
|
||||
assert(App::I.is_render_thread());
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user