summaryrefslogtreecommitdiff
path: root/drivers/gles3
diff options
context:
space:
mode:
authorBastiaan Olij <mux213@gmail.com>2019-03-31 00:03:49 +1100
committerBastiaan Olij <mux213@gmail.com>2019-04-06 08:24:58 +1100
commit8349d4fbd99052db5a2e66a4ff9b3d44e3ceabac (patch)
treeab73969dbcfaf88456042aeaecf6c38a44311ab4 /drivers/gles3
parentcc349336e7a099f786c8c281fdceefd7d0bd33ae (diff)
Add option to have viewport render into supplied texture
Diffstat (limited to 'drivers/gles3')
-rw-r--r--drivers/gles3/rasterizer_gles3.cpp15
-rw-r--r--drivers/gles3/rasterizer_gles3.h2
-rw-r--r--drivers/gles3/rasterizer_scene_gles3.cpp12
-rw-r--r--drivers/gles3/rasterizer_storage_gles3.cpp112
-rw-r--r--drivers/gles3/rasterizer_storage_gles3.h11
5 files changed, 145 insertions, 7 deletions
diff --git a/drivers/gles3/rasterizer_gles3.cpp b/drivers/gles3/rasterizer_gles3.cpp
index a4e042ae0e..96db7a11ef 100644
--- a/drivers/gles3/rasterizer_gles3.cpp
+++ b/drivers/gles3/rasterizer_gles3.cpp
@@ -253,11 +253,16 @@ void RasterizerGLES3::set_current_render_target(RID p_render_target) {
}
}
-void RasterizerGLES3::restore_render_target() {
+void RasterizerGLES3::restore_render_target(bool p_3d_was_drawn) {
ERR_FAIL_COND(storage->frame.current_rt == NULL);
RasterizerStorageGLES3::RenderTarget *rt = storage->frame.current_rt;
- glBindFramebuffer(GL_FRAMEBUFFER, rt->fbo);
+ if (p_3d_was_drawn && rt->external.fbo != 0) {
+ // our external render buffer is now leading, render 2d into that.
+ glBindFramebuffer(GL_FRAMEBUFFER, rt->external.fbo);
+ } else {
+ glBindFramebuffer(GL_FRAMEBUFFER, rt->fbo);
+ }
glViewport(0, 0, rt->width, rt->height);
}
@@ -339,7 +344,11 @@ void RasterizerGLES3::blit_render_target_to_screen(RID p_render_target, const Re
#if 1
Size2 win_size = OS::get_singleton()->get_window_size();
- glBindFramebuffer(GL_READ_FRAMEBUFFER, rt->fbo);
+ if (rt->external.fbo != 0) {
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, rt->external.fbo);
+ } else {
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, rt->fbo);
+ }
glReadBuffer(GL_COLOR_ATTACHMENT0);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, RasterizerStorageGLES3::system_fbo);
glBlitFramebuffer(0, 0, rt->width, rt->height, p_screen_rect.position.x, win_size.height - p_screen_rect.position.y - p_screen_rect.size.height, p_screen_rect.position.x + p_screen_rect.size.width, win_size.height - p_screen_rect.position.y, GL_COLOR_BUFFER_BIT, GL_NEAREST);
diff --git a/drivers/gles3/rasterizer_gles3.h b/drivers/gles3/rasterizer_gles3.h
index 7541c55c82..ad0d004c9d 100644
--- a/drivers/gles3/rasterizer_gles3.h
+++ b/drivers/gles3/rasterizer_gles3.h
@@ -56,7 +56,7 @@ public:
virtual void initialize();
virtual void begin_frame(double frame_step);
virtual void set_current_render_target(RID p_render_target);
- virtual void restore_render_target();
+ virtual void restore_render_target(bool p_3d_was_drawn);
virtual void clear_render_target(const Color &p_color);
virtual void blit_render_target_to_screen(RID p_render_target, const Rect2 &p_screen_rect, int p_screen = 0);
virtual void output_lens_distorted_to_screen(RID p_render_target, const Rect2 &p_screen_rect, float p_k1, float p_k2, const Vector2 &p_eye_center, float p_oversample);
diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp
index df8bd9feb0..0460e98e28 100644
--- a/drivers/gles3/rasterizer_scene_gles3.cpp
+++ b/drivers/gles3/rasterizer_scene_gles3.cpp
@@ -3660,7 +3660,11 @@ void RasterizerSceneGLES3::_post_process(Environment *env, const CameraMatrix &p
if (!env || storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT] || storage->frame.current_rt->width < 4 || storage->frame.current_rt->height < 4) { //no post process on small render targets
//no environment or transparent render, simply return and convert to SRGB
- glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->fbo);
+ if (storage->frame.current_rt->external.fbo != 0) {
+ glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->external.fbo);
+ } else {
+ glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->fbo);
+ }
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->effects.mip_maps[0].color);
storage->shaders.copy.set_conditional(CopyShaderGLES3::LINEAR_TO_SRGB, true);
@@ -4003,7 +4007,11 @@ void RasterizerSceneGLES3::_post_process(Environment *env, const CameraMatrix &p
glViewport(0, 0, storage->frame.current_rt->width, storage->frame.current_rt->height);
}
- glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->fbo);
+ if (storage->frame.current_rt->external.fbo != 0) {
+ glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->external.fbo);
+ } else {
+ glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->fbo);
+ }
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, composite_from);
diff --git a/drivers/gles3/rasterizer_storage_gles3.cpp b/drivers/gles3/rasterizer_storage_gles3.cpp
index 51e36c1d7e..dc2f8d352a 100644
--- a/drivers/gles3/rasterizer_storage_gles3.cpp
+++ b/drivers/gles3/rasterizer_storage_gles3.cpp
@@ -6794,6 +6794,24 @@ void RasterizerStorageGLES3::_render_target_clear(RenderTarget *rt) {
glDeleteTextures(1, &rt->exposure.color);
rt->exposure.fbo = 0;
}
+
+ if (rt->external.fbo != 0) {
+ // free this
+ glDeleteFramebuffers(1, &rt->external.fbo);
+
+ // clean up our texture
+ Texture *t = texture_owner.get(rt->external.texture);
+ t->alloc_height = 0;
+ t->alloc_width = 0;
+ t->width = 0;
+ t->height = 0;
+ t->active = false;
+ texture_owner.free(rt->external.texture);
+ memdelete(t);
+
+ rt->external.fbo = 0;
+ }
+
Texture *tex = texture_owner.get(rt->texture);
tex->alloc_height = 0;
tex->alloc_width = 0;
@@ -7249,7 +7267,99 @@ RID RasterizerStorageGLES3::render_target_get_texture(RID p_render_target) const
RenderTarget *rt = render_target_owner.getornull(p_render_target);
ERR_FAIL_COND_V(!rt, RID());
- return rt->texture;
+ if (rt->external.fbo == 0) {
+ return rt->texture;
+ } else {
+ return rt->external.texture;
+ }
+}
+
+void RasterizerStorageGLES3::render_target_set_external_texture(RID p_render_target, unsigned int p_texture_id) {
+ RenderTarget *rt = render_target_owner.getornull(p_render_target);
+ ERR_FAIL_COND(!rt);
+
+ if (p_texture_id == 0) {
+ if (rt->external.fbo != 0) {
+ // free this
+ glDeleteFramebuffers(1, &rt->external.fbo);
+
+ // clean up our texture
+ Texture *t = texture_owner.get(rt->external.texture);
+ t->alloc_height = 0;
+ t->alloc_width = 0;
+ t->width = 0;
+ t->height = 0;
+ t->active = false;
+ texture_owner.free(rt->external.texture);
+ memdelete(t);
+
+ rt->external.fbo = 0;
+ }
+ } else {
+ Texture *t;
+
+ if (rt->external.fbo == 0) {
+ // create our fbo
+ glGenFramebuffers(1, &rt->external.fbo);
+ glBindFramebuffer(GL_FRAMEBUFFER, rt->external.fbo);
+
+ // allocate a texture
+ t = memnew(Texture);
+
+ t->type = VS::TEXTURE_TYPE_2D;
+ t->flags = 0;
+ t->width = 0;
+ t->height = 0;
+ t->alloc_height = 0;
+ t->alloc_width = 0;
+ t->format = Image::FORMAT_RGBA8;
+ t->target = GL_TEXTURE_2D;
+ t->gl_format_cache = 0;
+ t->gl_internal_format_cache = 0;
+ t->gl_type_cache = 0;
+ t->data_size = 0;
+ t->compressed = false;
+ t->srgb = false;
+ t->total_data_size = 0;
+ t->ignore_mipmaps = false;
+ t->mipmaps = 1;
+ t->active = true;
+ t->tex_id = 0;
+ t->render_target = rt;
+
+ rt->external.texture = texture_owner.make_rid(t);
+ } else {
+ // bind our frame buffer
+ glBindFramebuffer(GL_FRAMEBUFFER, rt->external.fbo);
+
+ // find our texture
+ t = texture_owner.get(rt->external.texture);
+ }
+
+ // set our texture
+ t->tex_id = p_texture_id;
+
+ // size shouldn't be different
+ t->width = rt->width;
+ t->height = rt->height;
+ t->alloc_height = rt->width;
+ t->alloc_width = rt->height;
+
+ // is there a point to setting the internal formats? we don't know them..
+
+ // set our texture as the destination for our framebuffer
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, p_texture_id, 0);
+
+ // check status and unbind
+ GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+ glBindFramebuffer(GL_FRAMEBUFFER, RasterizerStorageGLES3::system_fbo);
+
+ if (status != GL_FRAMEBUFFER_COMPLETE) {
+ printf("framebuffer fail, status: %x\n", status);
+ }
+
+ ERR_FAIL_COND(status != GL_FRAMEBUFFER_COMPLETE);
+ }
}
void RasterizerStorageGLES3::render_target_set_flag(RID p_render_target, RenderTargetFlags p_flag, bool p_value) {
diff --git a/drivers/gles3/rasterizer_storage_gles3.h b/drivers/gles3/rasterizer_storage_gles3.h
index 330139e179..92916ed808 100644
--- a/drivers/gles3/rasterizer_storage_gles3.h
+++ b/drivers/gles3/rasterizer_storage_gles3.h
@@ -1345,6 +1345,15 @@ public:
fbo(0) {}
} exposure;
+ // External FBO to render our final result to (mostly used for ARVR)
+ struct External {
+ GLuint fbo;
+ RID texture;
+
+ External() :
+ fbo(0) {}
+ } external;
+
uint64_t last_exposure_tick;
int width, height;
@@ -1366,6 +1375,7 @@ public:
msaa(VS::VIEWPORT_MSAA_DISABLED) {
exposure.fbo = 0;
buffers.fbo = 0;
+ external.fbo = 0;
for (int i = 0; i < RENDER_TARGET_FLAG_MAX; i++) {
flags[i] = false;
}
@@ -1383,6 +1393,7 @@ public:
virtual RID render_target_create();
virtual void render_target_set_size(RID p_render_target, int p_width, int p_height);
virtual RID render_target_get_texture(RID p_render_target) const;
+ virtual void render_target_set_external_texture(RID p_render_target, unsigned int p_texture_id);
virtual void render_target_set_flag(RID p_render_target, RenderTargetFlags p_flag, bool p_value);
virtual bool render_target_was_used(RID p_render_target);