ARVR GDNative enhancements:

- add set_interface function
- add access to depth buffer
- add supplying a depth buffer from an ARVR plugin
This commit is contained in:
Bastiaan Olij 2021-03-25 22:15:23 +11:00
parent 15ff752737
commit 717f3227ec
13 changed files with 189 additions and 20 deletions

View file

@ -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) {}

View file

@ -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);

View file

@ -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);

View file

@ -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);
}
}

View file

@ -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);

View file

@ -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;
}
}

View file

@ -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();

View file

@ -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",

View file

@ -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

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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);