diff --git a/drivers/dummy/rasterizer_dummy.h b/drivers/dummy/rasterizer_dummy.h index d3314cf5108..14ce7089385 100644 --- a/drivers/dummy/rasterizer_dummy.h +++ b/drivers/dummy/rasterizer_dummy.h @@ -705,7 +705,8 @@ public: void render_target_set_position(RID p_render_target, int p_x, int p_y) {} void render_target_set_size(RID p_render_target, int p_width, int p_height) {} RID render_target_get_texture(RID p_render_target) const { return RID(); } - void render_target_set_external_texture(RID p_render_target, unsigned int p_texture_id) {} + uint32_t render_target_get_depth_texture_id(RID p_render_target) const { return 0; } + void render_target_set_external_texture(RID p_render_target, unsigned int p_texture_id, unsigned int p_depth_id) {} void render_target_set_flag(RID p_render_target, RenderTargetFlags p_flag, bool p_value) {} bool render_target_was_used(RID p_render_target) { return false; } void render_target_clear_used(RID p_render_target) {} diff --git a/drivers/gles2/rasterizer_storage_gles2.cpp b/drivers/gles2/rasterizer_storage_gles2.cpp index 19b818c86c8..38b20227d07 100644 --- a/drivers/gles2/rasterizer_storage_gles2.cpp +++ b/drivers/gles2/rasterizer_storage_gles2.cpp @@ -5172,7 +5172,14 @@ void RasterizerStorageGLES2::_render_target_clear(RenderTarget *rt) { texture_owner.free(rt->external.texture); memdelete(t); + if (rt->external.depth != 0 && rt->external.depth_owned) { + glDeleteRenderbuffers(1, &rt->external.depth); + } + rt->external.fbo = 0; + rt->external.color = 0; + rt->external.depth = 0; + rt->external.depth_owned = false; } if (rt->depth) { @@ -5297,7 +5304,19 @@ RID RasterizerStorageGLES2::render_target_get_texture(RID p_render_target) const } } -void RasterizerStorageGLES2::render_target_set_external_texture(RID p_render_target, unsigned int p_texture_id) { +uint32_t RasterizerStorageGLES2::render_target_get_depth_texture_id(RID p_render_target) const { + + RenderTarget *rt = render_target_owner.getornull(p_render_target); + ERR_FAIL_COND_V(!rt, 0); + + if (rt->external.depth == 0) { + return rt->depth; + } else { + return rt->external.depth; + } +} + +void RasterizerStorageGLES2::render_target_set_external_texture(RID p_render_target, unsigned int p_texture_id, unsigned int p_depth_id) { RenderTarget *rt = render_target_owner.getornull(p_render_target); ERR_FAIL_COND(!rt); @@ -5307,7 +5326,7 @@ void RasterizerStorageGLES2::render_target_set_external_texture(RID p_render_tar glDeleteFramebuffers(1, &rt->external.fbo); // and this - if (rt->external.depth != 0) { + if (rt->external.depth != 0 && rt->external.depth_owned) { glDeleteRenderbuffers(1, &rt->external.depth); } @@ -5387,15 +5406,31 @@ void RasterizerStorageGLES2::render_target_set_external_texture(RID p_render_tar // On any other hardware these two modes are ignored and we do not have any MSAA, // the normal MSAA modes need to be used to enable our two pass approach + // If we created a depth buffer before and we're now passed one, we need to clear it out + if (rt->external.depth != 0 && rt->external.depth_owned && p_depth_id != 0) { + glDeleteRenderbuffers(1, &rt->external.depth); + rt->external.depth_owned = false; + rt->external.depth = 0; + } + + if (!rt->external.depth_owned) { + rt->external.depth = p_depth_id; + } + static const int msaa_value[] = { 2, 4 }; int msaa = msaa_value[rt->msaa - VS::VIEWPORT_MSAA_EXT_2X]; if (rt->external.depth == 0) { + rt->external.depth_owned = true; + // create a multisample depth buffer, we're not reusing Godots because Godot's didn't get created.. glGenRenderbuffers(1, &rt->external.depth); glBindRenderbuffer(GL_RENDERBUFFER, rt->external.depth); glRenderbufferStorageMultisample(GL_RENDERBUFFER, msaa, config.depth_buffer_internalformat, rt->width, rt->height); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rt->external.depth); + } else if (!rt->external.depth_owned) { + // we make an exception here, external plugin MUST make sure this is a proper multisample render buffer! + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rt->external.depth); } // and set our external texture as the texture... @@ -5404,11 +5439,20 @@ void RasterizerStorageGLES2::render_target_set_external_texture(RID p_render_tar } else #endif { + // if MSAA as on before, clear our render buffer + if (rt->external.depth != 0 && rt->external.depth_owned) { + glDeleteRenderbuffers(1, &rt->external.depth); + } + rt->external.depth_owned = false; + rt->external.depth = p_depth_id; + // set our texture as the destination for our framebuffer glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, p_texture_id, 0); // seeing we're rendering into this directly, better also use our depth buffer, just use our existing one :) - if (config.support_depth_texture) { + if (rt->external.depth != 0) { + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, rt->external.depth, 0); + } else if (config.support_depth_texture) { glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, rt->depth, 0); } else { glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rt->depth); diff --git a/drivers/gles2/rasterizer_storage_gles2.h b/drivers/gles2/rasterizer_storage_gles2.h index 264d0e65849..10af6a94e10 100644 --- a/drivers/gles2/rasterizer_storage_gles2.h +++ b/drivers/gles2/rasterizer_storage_gles2.h @@ -1230,12 +1230,14 @@ public: GLuint fbo; GLuint color; GLuint depth; + bool depth_owned; RID texture; External() : fbo(0), color(0), - depth(0) { + depth(0), + depth_owned(false) { } } external; @@ -1288,7 +1290,8 @@ public: virtual void render_target_set_position(RID p_render_target, int p_x, int p_y); 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 uint32_t render_target_get_depth_texture_id(RID p_render_target) const; + virtual void render_target_set_external_texture(RID p_render_target, unsigned int p_texture_id, unsigned int p_depth_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); diff --git a/drivers/gles3/rasterizer_storage_gles3.cpp b/drivers/gles3/rasterizer_storage_gles3.cpp index f1ca68809a1..b0acfb5d251 100644 --- a/drivers/gles3/rasterizer_storage_gles3.cpp +++ b/drivers/gles3/rasterizer_storage_gles3.cpp @@ -7196,6 +7196,8 @@ void RasterizerStorageGLES3::_render_target_clear(RenderTarget *rt) { memdelete(t); rt->external.fbo = 0; + rt->external.color = 0; + rt->external.depth = 0; } Texture *tex = texture_owner.get(rt->texture); @@ -7281,8 +7283,14 @@ void RasterizerStorageGLES3::_render_target_allocate(RenderTarget *rt) { glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, - GL_TEXTURE_2D, rt->depth, 0); + if (rt->external.depth == 0) { + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, + GL_TEXTURE_2D, rt->depth, 0); + } else { + // Use our external depth texture instead. + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, + GL_TEXTURE_2D, rt->external.depth, 0); + } glGenTextures(1, &rt->color); glBindTexture(GL_TEXTURE_2D, rt->color); @@ -7664,12 +7672,31 @@ RID RasterizerStorageGLES3::render_target_get_texture(RID p_render_target) const } } -void RasterizerStorageGLES3::render_target_set_external_texture(RID p_render_target, unsigned int p_texture_id) { +uint32_t RasterizerStorageGLES3::render_target_get_depth_texture_id(RID p_render_target) const { + + RenderTarget *rt = render_target_owner.getornull(p_render_target); + ERR_FAIL_COND_V(!rt, 0); + + if (rt->external.depth == 0) { + return rt->depth; + } else { + return rt->external.depth; + } +} + +void RasterizerStorageGLES3::render_target_set_external_texture(RID p_render_target, unsigned int p_texture_id, unsigned int p_depth_id) { RenderTarget *rt = render_target_owner.getornull(p_render_target); ERR_FAIL_COND(!rt); if (p_texture_id == 0) { if (rt->external.fbo != 0) { + // return to our original depth buffer + if (rt->external.depth != 0 && rt->fbo != 0) { + glBindFramebuffer(GL_FRAMEBUFFER, rt->fbo); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, rt->depth, 0); + glBindFramebuffer(GL_FRAMEBUFFER, RasterizerStorageGLES3::system_fbo); + } + // free this glDeleteFramebuffers(1, &rt->external.fbo); @@ -7684,6 +7711,8 @@ void RasterizerStorageGLES3::render_target_set_external_texture(RID p_render_tar memdelete(t); rt->external.fbo = 0; + rt->external.color = 0; + rt->external.depth = 0; } } else { Texture *t; @@ -7728,6 +7757,7 @@ void RasterizerStorageGLES3::render_target_set_external_texture(RID p_render_tar // set our texture t->tex_id = p_texture_id; + rt->external.color = p_texture_id; // size shouldn't be different t->width = rt->width; @@ -7740,14 +7770,32 @@ void RasterizerStorageGLES3::render_target_set_external_texture(RID p_render_tar // 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 + // check status GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); - glBindFramebuffer(GL_FRAMEBUFFER, RasterizerStorageGLES3::system_fbo); - if (status != GL_FRAMEBUFFER_COMPLETE) { printf("framebuffer fail, status: %x\n", status); } + // Copy our depth texture id, + // if it's 0 then we don't use it, + // else we use it instead of our normal depth buffer + rt->external.depth = p_depth_id; + + if (rt->external.depth != 0 && rt->fbo != 0) { + // Use our external depth texture instead. + glBindFramebuffer(GL_FRAMEBUFFER, rt->fbo); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, rt->external.depth, 0); + + // check status + GLenum status2 = glCheckFramebufferStatus(GL_FRAMEBUFFER); + if (status2 != GL_FRAMEBUFFER_COMPLETE) { + printf("framebuffer fail, status: %x\n", status2); + } + } + + // and unbind + glBindFramebuffer(GL_FRAMEBUFFER, RasterizerStorageGLES3::system_fbo); + ERR_FAIL_COND(status != GL_FRAMEBUFFER_COMPLETE); } } diff --git a/drivers/gles3/rasterizer_storage_gles3.h b/drivers/gles3/rasterizer_storage_gles3.h index 77c368e90ea..97fa405abb4 100644 --- a/drivers/gles3/rasterizer_storage_gles3.h +++ b/drivers/gles3/rasterizer_storage_gles3.h @@ -1400,10 +1400,15 @@ public: // External FBO to render our final result to (mostly used for ARVR) struct External { GLuint fbo; + GLuint color; + GLuint depth; RID texture; External() : - fbo(0) {} + fbo(0), + color(0), + depth(0) { + } } external; uint64_t last_exposure_tick; @@ -1450,7 +1455,8 @@ public: virtual void render_target_set_position(RID p_render_target, int p_x, int p_y); 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 uint32_t render_target_get_depth_texture_id(RID p_render_target) const; + virtual void render_target_set_external_texture(RID p_render_target, unsigned int p_texture_id, unsigned int p_depth_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); diff --git a/modules/gdnative/arvr/arvr_interface_gdnative.cpp b/modules/gdnative/arvr/arvr_interface_gdnative.cpp index 48493e0bbdb..46eccdd0422 100644 --- a/modules/gdnative/arvr/arvr_interface_gdnative.cpp +++ b/modules/gdnative/arvr/arvr_interface_gdnative.cpp @@ -216,6 +216,17 @@ unsigned int ARVRInterfaceGDNative::get_external_texture_for_eye(ARVRInterface:: } } +unsigned int ARVRInterfaceGDNative::get_external_depth_for_eye(ARVRInterface::Eyes p_eye) { + + ERR_FAIL_COND_V(interface == NULL, 0); + + if ((interface->version.major > 1) || ((interface->version.major) == 1 && (interface->version.minor >= 2))) { + return (unsigned int)interface->get_external_depth_for_eye(data, (godot_int)p_eye); + } else { + return 0; + } +} + void ARVRInterfaceGDNative::commit_for_eye(ARVRInterface::Eyes p_eye, RID p_render_target, const Rect2 &p_screen_rect) { ERR_FAIL_COND(interface == NULL); @@ -425,4 +436,21 @@ godot_real GDAPI godot_arvr_get_controller_rumble(godot_int p_controller_id) { return 0.0; } + +void GDAPI godot_arvr_set_interface(godot_object *p_arvr_interface, const godot_arvr_interface_gdnative *p_gdn_interface) { + // If our major version is 0 or bigger then 10, we're likely looking at our constructor pointer from an older plugin + ERR_FAIL_COND_MSG((p_gdn_interface->version.major == 0) || (p_gdn_interface->version.major > 10), "GDNative ARVR interfaces build for Godot 3.0 are not supported."); + + ARVRInterfaceGDNative *interface = (ARVRInterfaceGDNative *)p_arvr_interface; + interface->set_interface((const godot_arvr_interface_gdnative *)p_gdn_interface); +} + +godot_int GDAPI godot_arvr_get_depthid(godot_rid *p_render_target) { + // We also need to access our depth texture for reprojection. + RID *render_target = (RID *)p_render_target; + + uint32_t texid = VSG::storage->render_target_get_depth_texture_id(*render_target); + + return texid; +} } diff --git a/modules/gdnative/arvr/arvr_interface_gdnative.h b/modules/gdnative/arvr/arvr_interface_gdnative.h index 4fc7db06198..6de72855c08 100644 --- a/modules/gdnative/arvr/arvr_interface_gdnative.h +++ b/modules/gdnative/arvr/arvr_interface_gdnative.h @@ -82,6 +82,7 @@ public: virtual CameraMatrix get_projection_for_eye(ARVRInterface::Eyes p_eye, real_t p_aspect, real_t p_z_near, real_t p_z_far); virtual unsigned int get_external_texture_for_eye(ARVRInterface::Eyes p_eye); + virtual unsigned int get_external_depth_for_eye(ARVRInterface::Eyes p_eye); virtual void commit_for_eye(ARVRInterface::Eyes p_eye, RID p_render_target, const Rect2 &p_screen_rect); virtual void process(); diff --git a/modules/gdnative/gdnative_api.json b/modules/gdnative/gdnative_api.json index e011c787bab..3a56a25e9f7 100644 --- a/modules/gdnative/gdnative_api.json +++ b/modules/gdnative/gdnative_api.json @@ -6459,7 +6459,32 @@ "major": 1, "minor": 1 }, - "next": null, + "next": { + "name": "arvr", + "type": "ARVR", + "version": { + "major": 1, + "minor": 2 + }, + "next": null, + "api": [ + { + "name": "godot_arvr_set_interface", + "return_type": "void", + "arguments": [ + ["godot_object *", "p_arvr_interface"], + ["const godot_arvr_interface_gdnative *", "p_gdn_interface"] + ] + }, + { + "name": "godot_arvr_get_depthid", + "return_type": "godot_int", + "arguments": [ + ["godot_rid *", "p_render_target"] + ] + } + ] + }, "api": [ { "name": "godot_arvr_register_interface", diff --git a/modules/gdnative/include/arvr/godot_arvr.h b/modules/gdnative/include/arvr/godot_arvr.h index 4ddc9335e48..2e5b832617b 100644 --- a/modules/gdnative/include/arvr/godot_arvr.h +++ b/modules/gdnative/include/arvr/godot_arvr.h @@ -42,7 +42,7 @@ extern "C" { // Use these to populate version in your plugin #define GODOTVR_API_MAJOR 1 -#define GODOTVR_API_MINOR 1 +#define GODOTVR_API_MINOR 2 typedef struct { godot_gdnative_api_version version; /* version of our API */ @@ -65,6 +65,8 @@ typedef struct { godot_int (*get_external_texture_for_eye)(void *, godot_int); void (*notification)(void *, godot_int); godot_int (*get_camera_feed_id)(void *); + // only in 1.2 onwards + godot_int (*get_external_depth_for_eye)(void *, godot_int); } godot_arvr_interface_gdnative; void GDAPI godot_arvr_register_interface(const godot_arvr_interface_gdnative *p_interface); @@ -85,6 +87,10 @@ void GDAPI godot_arvr_set_controller_button(godot_int p_controller_id, godot_int void GDAPI godot_arvr_set_controller_axis(godot_int p_controller_id, godot_int p_axis, godot_real p_value, godot_bool p_can_be_negative); godot_real GDAPI godot_arvr_get_controller_rumble(godot_int p_controller_id); +// ARVR 1.2 functions +void GDAPI godot_arvr_set_interface(godot_object *p_arvr_interface, const godot_arvr_interface_gdnative *p_gdn_interface); +godot_int GDAPI godot_arvr_get_depthid(godot_rid *p_render_target); + #ifdef __cplusplus } #endif diff --git a/servers/arvr/arvr_interface.cpp b/servers/arvr/arvr_interface.cpp index a1d01e1e75a..42afef442d5 100644 --- a/servers/arvr/arvr_interface.cpp +++ b/servers/arvr/arvr_interface.cpp @@ -129,6 +129,11 @@ unsigned int ARVRInterface::get_external_texture_for_eye(ARVRInterface::Eyes p_e return 0; }; +// optional render to external depth texture which enhances performance on those platforms that require us to submit our end result into special textures. +unsigned int ARVRInterface::get_external_depth_for_eye(ARVRInterface::Eyes p_eye) { + return 0; +}; + /** these will only be implemented on AR interfaces, so we want dummies for VR **/ bool ARVRInterface::get_anchor_detection_is_enabled() const { return false; diff --git a/servers/arvr/arvr_interface.h b/servers/arvr/arvr_interface.h index b10b2808e98..292ed9d1feb 100644 --- a/servers/arvr/arvr_interface.h +++ b/servers/arvr/arvr_interface.h @@ -110,6 +110,7 @@ public: virtual Transform get_transform_for_eye(ARVRInterface::Eyes p_eye, const Transform &p_cam_transform) = 0; /* get each eyes camera transform, also implement EYE_MONO */ virtual CameraMatrix get_projection_for_eye(ARVRInterface::Eyes p_eye, real_t p_aspect, real_t p_z_near, real_t p_z_far) = 0; /* get each eyes projection matrix */ virtual unsigned int get_external_texture_for_eye(ARVRInterface::Eyes p_eye); /* if applicable return external texture to render to */ + virtual unsigned int get_external_depth_for_eye(ARVRInterface::Eyes p_eye); /* if applicable return external depth texture to render to */ virtual void commit_for_eye(ARVRInterface::Eyes p_eye, RID p_render_target, const Rect2 &p_screen_rect) = 0; /* output the left or right eye */ virtual void process() = 0; diff --git a/servers/visual/rasterizer.h b/servers/visual/rasterizer.h index d594c4e05a5..1123e524c9d 100644 --- a/servers/visual/rasterizer.h +++ b/servers/visual/rasterizer.h @@ -573,7 +573,8 @@ public: virtual void render_target_set_position(RID p_render_target, int p_x, int p_y) = 0; virtual void render_target_set_size(RID p_render_target, int p_width, int p_height) = 0; virtual RID render_target_get_texture(RID p_render_target) const = 0; - virtual void render_target_set_external_texture(RID p_render_target, unsigned int p_texture_id) = 0; + virtual uint32_t render_target_get_depth_texture_id(RID p_render_target) const = 0; + virtual void render_target_set_external_texture(RID p_render_target, unsigned int p_texture_id, unsigned int p_depth_id) = 0; virtual void render_target_set_flag(RID p_render_target, RenderTargetFlags p_flag, bool p_value) = 0; virtual bool render_target_was_used(RID p_render_target) = 0; virtual void render_target_clear_used(RID p_render_target) = 0; diff --git a/servers/visual/visual_server_viewport.cpp b/servers/visual/visual_server_viewport.cpp index f4df196ee25..fe03a4ba68a 100644 --- a/servers/visual/visual_server_viewport.cpp +++ b/servers/visual/visual_server_viewport.cpp @@ -314,7 +314,7 @@ void VisualServerViewport::draw_viewports() { ARVRInterface::Eyes leftOrMono = arvr_interface->is_stereo() ? ARVRInterface::EYE_LEFT : ARVRInterface::EYE_MONO; // check for an external texture destination for our left eye/mono - VSG::storage->render_target_set_external_texture(vp->render_target, arvr_interface->get_external_texture_for_eye(leftOrMono)); + VSG::storage->render_target_set_external_texture(vp->render_target, arvr_interface->get_external_texture_for_eye(leftOrMono), arvr_interface->get_external_depth_for_eye(leftOrMono)); // set our render target as current VSG::rasterizer->set_current_render_target(vp->render_target); @@ -326,7 +326,7 @@ void VisualServerViewport::draw_viewports() { // render right eye if (leftOrMono == ARVRInterface::EYE_LEFT) { // check for an external texture destination for our right eye - VSG::storage->render_target_set_external_texture(vp->render_target, arvr_interface->get_external_texture_for_eye(ARVRInterface::EYE_RIGHT)); + VSG::storage->render_target_set_external_texture(vp->render_target, arvr_interface->get_external_texture_for_eye(ARVRInterface::EYE_RIGHT), arvr_interface->get_external_depth_for_eye(ARVRInterface::EYE_RIGHT)); // commit for eye may have changed the render target VSG::rasterizer->set_current_render_target(vp->render_target); @@ -338,7 +338,7 @@ void VisualServerViewport::draw_viewports() { // and for our frame timing, mark when we've finished committing our eyes ARVRServer::get_singleton()->_mark_commit(); } else { - VSG::storage->render_target_set_external_texture(vp->render_target, 0); + VSG::storage->render_target_set_external_texture(vp->render_target, 0, 0); VSG::rasterizer->set_current_render_target(vp->render_target); VSG::scene_render->set_debug_draw_mode(vp->debug_draw);