Add multiview to the opengl3 driver

This commit is contained in:
David Snopek 2022-09-04 09:56:24 -05:00
parent a8c805be29
commit 398ee08375
24 changed files with 423 additions and 81 deletions

View File

@ -274,15 +274,32 @@ RasterizerGLES3::~RasterizerGLES3() {
void RasterizerGLES3::prepare_for_blitting_render_targets() { void RasterizerGLES3::prepare_for_blitting_render_targets() {
} }
void RasterizerGLES3::_blit_render_target_to_screen(RID p_render_target, DisplayServer::WindowID p_screen, const Rect2 &p_screen_rect) { void RasterizerGLES3::_blit_render_target_to_screen(RID p_render_target, DisplayServer::WindowID p_screen, const Rect2 &p_screen_rect, uint32_t p_layer) {
GLES3::RenderTarget *rt = GLES3::TextureStorage::get_singleton()->get_render_target(p_render_target); GLES3::RenderTarget *rt = GLES3::TextureStorage::get_singleton()->get_render_target(p_render_target);
ERR_FAIL_COND(!rt); ERR_FAIL_COND(!rt);
GLuint read_fbo = 0;
if (rt->view_count > 1) {
glGenFramebuffers(1, &read_fbo);
glBindFramebuffer(GL_READ_FRAMEBUFFER, read_fbo);
glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, rt->color, 0, p_layer);
} else {
glBindFramebuffer(GL_READ_FRAMEBUFFER, rt->fbo); glBindFramebuffer(GL_READ_FRAMEBUFFER, rt->fbo);
}
glReadBuffer(GL_COLOR_ATTACHMENT0); glReadBuffer(GL_COLOR_ATTACHMENT0);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, GLES3::TextureStorage::system_fbo); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, GLES3::TextureStorage::system_fbo);
// Flip content upside down to correct for coordinates. // Flip content upside down to correct for coordinates.
glBlitFramebuffer(0, 0, rt->size.x, rt->size.y, 0, p_screen_rect.size.y, p_screen_rect.size.x, 0, GL_COLOR_BUFFER_BIT, GL_NEAREST); Vector2i screen_rect_end = p_screen_rect.get_end();
glBlitFramebuffer(0, 0, rt->size.x, rt->size.y,
p_screen_rect.position.x, screen_rect_end.y, screen_rect_end.x, p_screen_rect.position.y,
GL_COLOR_BUFFER_BIT, GL_NEAREST);
if (read_fbo != 0) {
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
glDeleteFramebuffers(1, &read_fbo);
}
} }
// is this p_screen useless in a multi window environment? // is this p_screen useless in a multi window environment?
@ -293,7 +310,7 @@ void RasterizerGLES3::blit_render_targets_to_screen(DisplayServer::WindowID p_sc
RID rid_rt = blit.render_target; RID rid_rt = blit.render_target;
Rect2 dst_rect = blit.dst_rect; Rect2 dst_rect = blit.dst_rect;
_blit_render_target_to_screen(rid_rt, p_screen, dst_rect); _blit_render_target_to_screen(rid_rt, p_screen, dst_rect, blit.multi_view.use_layer ? blit.multi_view.layer : 0);
} }
} }

View File

@ -68,7 +68,7 @@ protected:
RasterizerCanvasGLES3 *canvas = nullptr; RasterizerCanvasGLES3 *canvas = nullptr;
RasterizerSceneGLES3 *scene = nullptr; RasterizerSceneGLES3 *scene = nullptr;
void _blit_render_target_to_screen(RID p_render_target, DisplayServer::WindowID p_screen, const Rect2 &p_screen_rect); void _blit_render_target_to_screen(RID p_render_target, DisplayServer::WindowID p_screen, const Rect2 &p_screen_rect, uint32_t p_layer);
public: public:
RendererUtilities *get_utilities() { return utilities; } RendererUtilities *get_utilities() { return utilities; }

View File

@ -1273,6 +1273,19 @@ void RasterizerSceneGLES3::_setup_environment(const RenderDataGLES3 *p_render_da
GLES3::MaterialStorage::store_transform(p_render_data->cam_transform, scene_state.ubo.inv_view_matrix); GLES3::MaterialStorage::store_transform(p_render_data->cam_transform, scene_state.ubo.inv_view_matrix);
GLES3::MaterialStorage::store_transform(p_render_data->inv_cam_transform, scene_state.ubo.view_matrix); GLES3::MaterialStorage::store_transform(p_render_data->inv_cam_transform, scene_state.ubo.view_matrix);
if (p_render_data->view_count > 1) {
for (uint32_t v = 0; v < p_render_data->view_count; v++) {
projection = correction * p_render_data->view_projection[v];
GLES3::MaterialStorage::store_camera(projection, scene_state.multiview_ubo.projection_matrix_view[v]);
GLES3::MaterialStorage::store_camera(projection.inverse(), scene_state.multiview_ubo.inv_projection_matrix_view[v]);
scene_state.multiview_ubo.eye_offset[v][0] = p_render_data->view_eye_offset[v].x;
scene_state.multiview_ubo.eye_offset[v][1] = p_render_data->view_eye_offset[v].y;
scene_state.multiview_ubo.eye_offset[v][2] = p_render_data->view_eye_offset[v].z;
scene_state.multiview_ubo.eye_offset[v][3] = 0.0;
}
}
scene_state.ubo.directional_light_count = p_render_data->directional_light_count; scene_state.ubo.directional_light_count = p_render_data->directional_light_count;
scene_state.ubo.z_far = p_render_data->z_far; scene_state.ubo.z_far = p_render_data->z_far;
@ -1374,6 +1387,15 @@ void RasterizerSceneGLES3::_setup_environment(const RenderDataGLES3 *p_render_da
glBindBufferBase(GL_UNIFORM_BUFFER, SCENE_DATA_UNIFORM_LOCATION, scene_state.ubo_buffer); glBindBufferBase(GL_UNIFORM_BUFFER, SCENE_DATA_UNIFORM_LOCATION, scene_state.ubo_buffer);
glBufferData(GL_UNIFORM_BUFFER, sizeof(SceneState::UBO), &scene_state.ubo, GL_STREAM_DRAW); glBufferData(GL_UNIFORM_BUFFER, sizeof(SceneState::UBO), &scene_state.ubo, GL_STREAM_DRAW);
glBindBuffer(GL_UNIFORM_BUFFER, 0); glBindBuffer(GL_UNIFORM_BUFFER, 0);
if (p_render_data->view_count > 1) {
if (scene_state.multiview_buffer == 0) {
glGenBuffers(1, &scene_state.multiview_buffer);
}
glBindBufferBase(GL_UNIFORM_BUFFER, SCENE_MULTIVIEW_UNIFORM_LOCATION, scene_state.multiview_buffer);
glBufferData(GL_UNIFORM_BUFFER, sizeof(SceneState::MultiviewUBO), &scene_state.multiview_ubo, GL_STREAM_DRAW);
glBindBuffer(GL_UNIFORM_BUFFER, 0);
}
} }
// Puts lights into Uniform Buffers. Needs to be called before _fill_list as this caches the index of each light in the Uniform Buffer // Puts lights into Uniform Buffers. Needs to be called before _fill_list as this caches the index of each light in the Uniform Buffer
@ -1916,8 +1938,14 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params,
GLES3::SceneShaderData *prev_shader = nullptr; GLES3::SceneShaderData *prev_shader = nullptr;
GeometryInstanceGLES3 *prev_inst = nullptr; GeometryInstanceGLES3 *prev_inst = nullptr;
SceneShaderGLES3::ShaderVariant prev_variant = SceneShaderGLES3::ShaderVariant::MODE_COLOR; SceneShaderGLES3::ShaderVariant prev_variant = SceneShaderGLES3::ShaderVariant::MODE_COLOR;
SceneShaderGLES3::ShaderVariant shader_variant = SceneShaderGLES3::MODE_COLOR; // Assigned to silence wrong -Wmaybe-initialized
SceneShaderGLES3::ShaderVariant shader_variant = SceneShaderGLES3::MODE_COLOR; // Assigned to silence wrong -Wmaybe-initialized. // @todo Get this from p_params->spec_constant_base_flags instead of hardcoding it.
uint32_t base_spec_constants = 0;
if (p_render_data->view_count > 1) {
base_spec_constants |= 1 << SPEC_CONSTANT_USE_MULTIVIEW;
}
switch (p_pass_mode) { switch (p_pass_mode) {
case PASS_MODE_COLOR: case PASS_MODE_COLOR:
@ -1957,8 +1985,6 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params,
continue; continue;
} }
//uint32_t base_spec_constants = p_params->spec_constant_base_flags;
GLES3::SceneShaderData *shader; GLES3::SceneShaderData *shader;
GLES3::SceneMaterialData *material_data; GLES3::SceneMaterialData *material_data;
void *mesh_surface; void *mesh_surface;
@ -2128,7 +2154,7 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params,
} }
if (prev_shader != shader || prev_variant != instance_variant) { if (prev_shader != shader || prev_variant != instance_variant) {
material_storage->shaders.scene_shader.version_bind_shader(shader->version, instance_variant); material_storage->shaders.scene_shader.version_bind_shader(shader->version, instance_variant, base_spec_constants);
float opaque_prepass_threshold = 0.0; float opaque_prepass_threshold = 0.0;
if constexpr (p_pass_mode == PASS_MODE_DEPTH) { if constexpr (p_pass_mode == PASS_MODE_DEPTH) {
opaque_prepass_threshold = 0.99; opaque_prepass_threshold = 0.99;
@ -2136,7 +2162,7 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params,
opaque_prepass_threshold = 0.1; opaque_prepass_threshold = 0.1;
} }
material_storage->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::OPAQUE_PREPASS_THRESHOLD, opaque_prepass_threshold, shader->version, instance_variant); material_storage->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::OPAQUE_PREPASS_THRESHOLD, opaque_prepass_threshold, shader->version, instance_variant, base_spec_constants);
prev_shader = shader; prev_shader = shader;
prev_variant = instance_variant; prev_variant = instance_variant;
@ -2144,21 +2170,21 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params,
if (prev_inst != inst || prev_shader != shader || prev_variant != instance_variant) { if (prev_inst != inst || prev_shader != shader || prev_variant != instance_variant) {
// Rebind the light indices. // Rebind the light indices.
material_storage->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::OMNI_LIGHT_COUNT, inst->omni_light_count, shader->version, instance_variant); material_storage->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::OMNI_LIGHT_COUNT, inst->omni_light_count, shader->version, instance_variant, base_spec_constants);
material_storage->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::SPOT_LIGHT_COUNT, inst->spot_light_count, shader->version, instance_variant); material_storage->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::SPOT_LIGHT_COUNT, inst->spot_light_count, shader->version, instance_variant, base_spec_constants);
if (inst->omni_light_count) { if (inst->omni_light_count) {
glUniform1uiv(material_storage->shaders.scene_shader.version_get_uniform(SceneShaderGLES3::OMNI_LIGHT_INDICES, shader->version, instance_variant), inst->omni_light_count, inst->omni_light_gl_cache.ptr()); glUniform1uiv(material_storage->shaders.scene_shader.version_get_uniform(SceneShaderGLES3::OMNI_LIGHT_INDICES, shader->version, instance_variant, base_spec_constants), inst->omni_light_count, inst->omni_light_gl_cache.ptr());
} }
if (inst->spot_light_count) { if (inst->spot_light_count) {
glUniform1uiv(material_storage->shaders.scene_shader.version_get_uniform(SceneShaderGLES3::SPOT_LIGHT_INDICES, shader->version, instance_variant), inst->spot_light_count, inst->spot_light_gl_cache.ptr()); glUniform1uiv(material_storage->shaders.scene_shader.version_get_uniform(SceneShaderGLES3::SPOT_LIGHT_INDICES, shader->version, instance_variant, base_spec_constants), inst->spot_light_count, inst->spot_light_gl_cache.ptr());
} }
prev_inst = inst; prev_inst = inst;
} }
material_storage->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::WORLD_TRANSFORM, world_transform, shader->version, instance_variant); material_storage->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::WORLD_TRANSFORM, world_transform, shader->version, instance_variant, base_spec_constants);
if (inst->instance_count > 0) { if (inst->instance_count > 0) {
// Using MultiMesh. // Using MultiMesh.
// Bind instance buffers. // Bind instance buffers.

View File

@ -74,6 +74,7 @@ enum SceneUniformLocation {
SCENE_OMNILIGHT_UNIFORM_LOCATION, SCENE_OMNILIGHT_UNIFORM_LOCATION,
SCENE_SPOTLIGHT_UNIFORM_LOCATION, SCENE_SPOTLIGHT_UNIFORM_LOCATION,
SCENE_DIRECTIONAL_LIGHT_UNIFORM_LOCATION, SCENE_DIRECTIONAL_LIGHT_UNIFORM_LOCATION,
SCENE_MULTIVIEW_UNIFORM_LOCATION,
}; };
enum SkyUniformLocation { enum SkyUniformLocation {
@ -90,6 +91,8 @@ enum {
SPEC_CONSTANT_DISABLE_OMNI_LIGHTS = 2, SPEC_CONSTANT_DISABLE_OMNI_LIGHTS = 2,
SPEC_CONSTANT_DISABLE_SPOT_LIGHTS = 3, SPEC_CONSTANT_DISABLE_SPOT_LIGHTS = 3,
SPEC_CONSTANT_DISABLE_FOG = 4, SPEC_CONSTANT_DISABLE_FOG = 4,
SPEC_CONSTANT_USE_RADIANCE_MAP = 5,
SPEC_CONSTANT_USE_MULTIVIEW = 6,
}; };
struct RenderDataGLES3 { struct RenderDataGLES3 {
@ -343,6 +346,13 @@ private:
}; };
static_assert(sizeof(UBO) % 16 == 0, "Scene UBO size must be a multiple of 16 bytes"); static_assert(sizeof(UBO) % 16 == 0, "Scene UBO size must be a multiple of 16 bytes");
struct MultiviewUBO {
float projection_matrix_view[RendererSceneRender::MAX_RENDER_VIEWS][16];
float inv_projection_matrix_view[RendererSceneRender::MAX_RENDER_VIEWS][16];
float eye_offset[RendererSceneRender::MAX_RENDER_VIEWS][4];
};
static_assert(sizeof(MultiviewUBO) % 16 == 0, "Multiview UBO size must be a multiple of 16 bytes");
struct TonemapUBO { struct TonemapUBO {
float exposure = 1.0; float exposure = 1.0;
float white = 1.0; float white = 1.0;
@ -353,6 +363,8 @@ private:
UBO ubo; UBO ubo;
GLuint ubo_buffer = 0; GLuint ubo_buffer = 0;
MultiviewUBO multiview_ubo;
GLuint multiview_buffer = 0;
GLuint tonemap_buffer = 0; GLuint tonemap_buffer = 0;
bool used_depth_prepass = false; bool used_depth_prepass = false;

View File

@ -142,7 +142,7 @@ RID ShaderGLES3::version_create() {
return version_owner.make_rid(version); return version_owner.make_rid(version);
} }
void ShaderGLES3::_build_variant_code(StringBuilder &builder, uint32_t p_variant, const Version *p_version, const StageTemplate &p_template, uint64_t p_specialization) { void ShaderGLES3::_build_variant_code(StringBuilder &builder, uint32_t p_variant, const Version *p_version, StageType p_stage_type, uint64_t p_specialization) {
#ifdef GLES_OVER_GL #ifdef GLES_OVER_GL
builder.append("#version 330\n"); builder.append("#version 330\n");
builder.append("#define USE_GLES_OVER_GL\n"); builder.append("#define USE_GLES_OVER_GL\n");
@ -171,6 +171,24 @@ void ShaderGLES3::_build_variant_code(StringBuilder &builder, uint32_t p_variant
} }
builder.append("\n"); //make sure defines begin at newline builder.append("\n"); //make sure defines begin at newline
// Insert multiview extension loading, because it needs to appear before
// any non-preprocessor code (like the "precision highp..." lines below).
builder.append("#ifdef USE_MULTIVIEW\n");
builder.append("#if defined(GL_OVR_multiview2)\n");
builder.append("#extension GL_OVR_multiview2 : require\n");
builder.append("#elif defined(GL_OVR_multiview)\n");
builder.append("#extension GL_OVR_multiview : require\n");
builder.append("#endif\n");
if (p_stage_type == StageType::STAGE_TYPE_VERTEX) {
builder.append("layout(num_views=2) in;\n");
}
builder.append("#define ViewIndex gl_ViewID_OVR\n");
builder.append("#define MAX_VIEWS 2\n");
builder.append("#else\n");
builder.append("#define ViewIndex 0\n");
builder.append("#define MAX_VIEWS 1\n");
builder.append("#endif\n");
// Default to highp precision unless specified otherwise. // Default to highp precision unless specified otherwise.
builder.append("precision highp float;\n"); builder.append("precision highp float;\n");
builder.append("precision highp int;\n"); builder.append("precision highp int;\n");
@ -180,8 +198,9 @@ void ShaderGLES3::_build_variant_code(StringBuilder &builder, uint32_t p_variant
builder.append("precision highp sampler2DArray;\n"); builder.append("precision highp sampler2DArray;\n");
#endif #endif
for (uint32_t i = 0; i < p_template.chunks.size(); i++) { const StageTemplate &stage_template = stage_templates[p_stage_type];
const StageTemplate::Chunk &chunk = p_template.chunks[i]; for (uint32_t i = 0; i < stage_template.chunks.size(); i++) {
const StageTemplate::Chunk &chunk = stage_template.chunks[i];
switch (chunk.type) { switch (chunk.type) {
case StageTemplate::Chunk::TYPE_MATERIAL_UNIFORMS: { case StageTemplate::Chunk::TYPE_MATERIAL_UNIFORMS: {
builder.append(p_version->uniforms.get_data()); //uniforms (same for vertex and fragment) builder.append(p_version->uniforms.get_data()); //uniforms (same for vertex and fragment)
@ -224,7 +243,7 @@ void ShaderGLES3::_compile_specialization(Version::Specialization &spec, uint32_
//vertex stage //vertex stage
{ {
StringBuilder builder; StringBuilder builder;
_build_variant_code(builder, p_variant, p_version, stage_templates[STAGE_TYPE_VERTEX], p_specialization); _build_variant_code(builder, p_variant, p_version, STAGE_TYPE_VERTEX, p_specialization);
spec.vert_id = glCreateShader(GL_VERTEX_SHADER); spec.vert_id = glCreateShader(GL_VERTEX_SHADER);
String builder_string = builder.as_string(); String builder_string = builder.as_string();
@ -272,7 +291,7 @@ void ShaderGLES3::_compile_specialization(Version::Specialization &spec, uint32_
//fragment stage //fragment stage
{ {
StringBuilder builder; StringBuilder builder;
_build_variant_code(builder, p_variant, p_version, stage_templates[STAGE_TYPE_FRAGMENT], p_specialization); _build_variant_code(builder, p_variant, p_version, STAGE_TYPE_FRAGMENT, p_specialization);
spec.frag_id = glCreateShader(GL_FRAGMENT_SHADER); spec.frag_id = glCreateShader(GL_FRAGMENT_SHADER);
String builder_string = builder.as_string(); String builder_string = builder.as_string();
@ -413,7 +432,7 @@ RS::ShaderNativeSourceCode ShaderGLES3::version_get_native_source_code(RID p_ver
{ {
StringBuilder builder; StringBuilder builder;
_build_variant_code(builder, i, version, stage_templates[STAGE_TYPE_VERTEX], specialization_default_mask); _build_variant_code(builder, i, version, STAGE_TYPE_VERTEX, specialization_default_mask);
RS::ShaderNativeSourceCode::Version::Stage stage; RS::ShaderNativeSourceCode::Version::Stage stage;
stage.name = "vertex"; stage.name = "vertex";
@ -425,7 +444,7 @@ RS::ShaderNativeSourceCode ShaderGLES3::version_get_native_source_code(RID p_ver
//fragment stage //fragment stage
{ {
StringBuilder builder; StringBuilder builder;
_build_variant_code(builder, i, version, stage_templates[STAGE_TYPE_FRAGMENT], specialization_default_mask); _build_variant_code(builder, i, version, STAGE_TYPE_FRAGMENT, specialization_default_mask);
RS::ShaderNativeSourceCode::Version::Stage stage; RS::ShaderNativeSourceCode::Version::Stage stage;
stage.name = "fragment"; stage.name = "fragment";

View File

@ -153,7 +153,7 @@ private:
StageTemplate stage_templates[STAGE_TYPE_MAX]; StageTemplate stage_templates[STAGE_TYPE_MAX];
void _build_variant_code(StringBuilder &p_builder, uint32_t p_variant, const Version *p_version, const StageTemplate &p_template, uint64_t p_specialization); void _build_variant_code(StringBuilder &p_builder, uint32_t p_variant, const Version *p_version, StageType p_stage_type, uint64_t p_specialization);
void _add_stage(const char *p_code, StageType p_stage_type); void _add_stage(const char *p_code, StageType p_stage_type);

View File

@ -16,6 +16,7 @@ DISABLE_LIGHT_OMNI = false
DISABLE_LIGHT_SPOT = false DISABLE_LIGHT_SPOT = false
DISABLE_FOG = false DISABLE_FOG = false
USE_RADIANCE_MAP = true USE_RADIANCE_MAP = true
USE_MULTIVIEW = false
#[vertex] #[vertex]
@ -153,6 +154,15 @@ layout(std140) uniform SceneData { // ubo:2
} }
scene_data; scene_data;
#ifdef USE_MULTIVIEW
layout(std140) uniform MultiviewData { // ubo:8
highp mat4 projection_matrix_view[MAX_VIEWS];
highp mat4 inv_projection_matrix_view[MAX_VIEWS];
highp vec4 eye_offset[MAX_VIEWS];
}
multiview_data;
#endif
uniform highp mat4 world_transform; uniform highp mat4 world_transform;
#ifdef USE_LIGHTMAP #ifdef USE_LIGHTMAP
@ -250,8 +260,14 @@ void main() {
#if defined(OVERRIDE_POSITION) #if defined(OVERRIDE_POSITION)
highp vec4 position; highp vec4 position;
#endif #endif
highp mat4 projection_matrix = scene_data.projection_matrix;
highp mat4 inv_projection_matrix = scene_data.inv_projection_matrix; #ifdef USE_MULTIVIEW
mat4 projection_matrix = multiview_data.projection_matrix_view[ViewIndex];
mat4 inv_projection_matrix = multiview_data.inv_projection_matrix_view[ViewIndex];
#else
mat4 projection_matrix = scene_data.projection_matrix;
mat4 inv_projection_matrix = scene_data.inv_projection_matrix;
#endif //USE_MULTIVIEW
#ifdef USE_INSTANCING #ifdef USE_INSTANCING
vec4 instance_custom = vec4(unpackHalf2x16(instance_color_custom_data.z), unpackHalf2x16(instance_color_custom_data.w)); vec4 instance_custom = vec4(unpackHalf2x16(instance_color_custom_data.z), unpackHalf2x16(instance_color_custom_data.w));
@ -339,7 +355,6 @@ void main() {
/* clang-format off */ /* clang-format off */
#[fragment] #[fragment]
// Default to SPECULAR_SCHLICK_GGX. // Default to SPECULAR_SCHLICK_GGX.
#if !defined(SPECULAR_DISABLED) && !defined(SPECULAR_SCHLICK_GGX) && !defined(SPECULAR_TOON) #if !defined(SPECULAR_DISABLED) && !defined(SPECULAR_SCHLICK_GGX) && !defined(SPECULAR_TOON)
#define SPECULAR_SCHLICK_GGX #define SPECULAR_SCHLICK_GGX
@ -463,6 +478,15 @@ layout(std140) uniform SceneData { // ubo:2
} }
scene_data; scene_data;
#ifdef USE_MULTIVIEW
layout(std140) uniform MultiviewData { // ubo:8
highp mat4 projection_matrix_view[MAX_VIEWS];
highp mat4 inv_projection_matrix_view[MAX_VIEWS];
highp vec4 eye_offset[MAX_VIEWS];
}
multiview_data;
#endif
/* clang-format off */ /* clang-format off */
#GLOBALS #GLOBALS
@ -530,8 +554,13 @@ uniform highp samplerCubeShadow positional_shadow; // texunit:-4
#endif // !defined(DISABLE_LIGHT_OMNI) && !defined(DISABLE_LIGHT_SPOT) #endif // !defined(DISABLE_LIGHT_OMNI) && !defined(DISABLE_LIGHT_SPOT)
uniform highp sampler2D screen_texture; // texunit:-5 #ifdef USE_MULTIVIEW
uniform highp sampler2DArray depth_buffer; // texunit:-6
uniform highp sampler2DArray screen_texture; // texunit:-5
#else
uniform highp sampler2D depth_buffer; // texunit:-6 uniform highp sampler2D depth_buffer; // texunit:-6
uniform highp sampler2D screen_texture; // texunit:-5
#endif
uniform highp mat4 world_transform; uniform highp mat4 world_transform;
uniform mediump float opaque_prepass_threshold; uniform mediump float opaque_prepass_threshold;
@ -884,7 +913,11 @@ vec4 fog_process(vec3 vertex) {
void main() { void main() {
//lay out everything, whatever is unused is optimized away anyway //lay out everything, whatever is unused is optimized away anyway
vec3 vertex = vertex_interp; vec3 vertex = vertex_interp;
#ifdef USE_MULTIVIEW
vec3 view = -normalize(vertex_interp - multiview_data.eye_offset[ViewIndex].xyz);
#else
vec3 view = -normalize(vertex_interp); vec3 view = -normalize(vertex_interp);
#endif
vec3 albedo = vec3(1.0); vec3 albedo = vec3(1.0);
vec3 backlight = vec3(0.0); vec3 backlight = vec3(0.0);
vec4 transmittance_color = vec4(0.0, 0.0, 0.0, 1.0); vec4 transmittance_color = vec4(0.0, 0.0, 0.0, 1.0);

View File

@ -44,7 +44,11 @@ in vec2 uv_interp;
layout(location = 0) out vec4 frag_color; layout(location = 0) out vec4 frag_color;
#ifdef USE_MULTIVIEW
uniform highp sampler2DArray source; //texunit:0
#else
uniform highp sampler2D source; //texunit:0 uniform highp sampler2D source; //texunit:0
#endif
#if defined(USE_GLOW_LEVEL1) || defined(USE_GLOW_LEVEL2) || defined(USE_GLOW_LEVEL3) || defined(USE_GLOW_LEVEL4) || defined(USE_GLOW_LEVEL5) || defined(USE_GLOW_LEVEL6) || defined(USE_GLOW_LEVEL7) #if defined(USE_GLOW_LEVEL1) || defined(USE_GLOW_LEVEL2) || defined(USE_GLOW_LEVEL3) || defined(USE_GLOW_LEVEL4) || defined(USE_GLOW_LEVEL5) || defined(USE_GLOW_LEVEL6) || defined(USE_GLOW_LEVEL7)
#define USING_GLOW // only use glow when at least one glow level is selected #define USING_GLOW // only use glow when at least one glow level is selected
@ -191,10 +195,17 @@ vec3 apply_fxaa(vec3 color, vec2 uv_interp, vec2 pixel_size) {
const float FXAA_REDUCE_MUL = (1.0 / 8.0); const float FXAA_REDUCE_MUL = (1.0 / 8.0);
const float FXAA_SPAN_MAX = 8.0; const float FXAA_SPAN_MAX = 8.0;
#ifdef USE_MULTIVIEW
vec3 rgbNW = textureLod(source, vec3(uv_interp + vec2(-1.0, -1.0) * pixel_size, ViewIndex), 0.0).xyz;
vec3 rgbNE = textureLod(source, vec3(uv_interp + vec2(1.0, -1.0) * pixel_size, ViewIndex), 0.0).xyz;
vec3 rgbSW = textureLod(source, vec3(uv_interp + vec2(-1.0, 1.0) * pixel_size, ViewIndex), 0.0).xyz;
vec3 rgbSE = textureLod(source, vec3(uv_interp + vec2(1.0, 1.0) * pixel_size, ViewIndex), 0.0).xyz;
#else
vec3 rgbNW = textureLod(source, uv_interp + vec2(-1.0, -1.0) * pixel_size, 0.0).xyz; vec3 rgbNW = textureLod(source, uv_interp + vec2(-1.0, -1.0) * pixel_size, 0.0).xyz;
vec3 rgbNE = textureLod(source, uv_interp + vec2(1.0, -1.0) * pixel_size, 0.0).xyz; vec3 rgbNE = textureLod(source, uv_interp + vec2(1.0, -1.0) * pixel_size, 0.0).xyz;
vec3 rgbSW = textureLod(source, uv_interp + vec2(-1.0, 1.0) * pixel_size, 0.0).xyz; vec3 rgbSW = textureLod(source, uv_interp + vec2(-1.0, 1.0) * pixel_size, 0.0).xyz;
vec3 rgbSE = textureLod(source, uv_interp + vec2(1.0, 1.0) * pixel_size, 0.0).xyz; vec3 rgbSE = textureLod(source, uv_interp + vec2(1.0, 1.0) * pixel_size, 0.0).xyz;
#endif
vec3 rgbM = color; vec3 rgbM = color;
vec3 luma = vec3(0.299, 0.587, 0.114); vec3 luma = vec3(0.299, 0.587, 0.114);
float lumaNW = dot(rgbNW, luma); float lumaNW = dot(rgbNW, luma);
@ -219,8 +230,13 @@ vec3 apply_fxaa(vec3 color, vec2 uv_interp, vec2 pixel_size) {
dir * rcpDirMin)) * dir * rcpDirMin)) *
pixel_size; pixel_size;
#ifdef USE_MULTIVIEW
vec3 rgbA = 0.5 * (textureLod(source, vec3(uv_interp + dir * (1.0 / 3.0 - 0.5), ViewIndex), 0.0).xyz + textureLod(source, vec3(uv_interp + dir * (2.0 / 3.0 - 0.5), ViewIndex), 0.0).xyz);
vec3 rgbB = rgbA * 0.5 + 0.25 * (textureLod(source, vec3(uv_interp + dir * -0.5, ViewIndex), 0.0).xyz + textureLod(source, vec3(uv_interp + dir * 0.5, ViewIndex), 0.0).xyz);
#else
vec3 rgbA = 0.5 * (textureLod(source, uv_interp + dir * (1.0 / 3.0 - 0.5), 0.0).xyz + textureLod(source, uv_interp + dir * (2.0 / 3.0 - 0.5), 0.0).xyz); vec3 rgbA = 0.5 * (textureLod(source, uv_interp + dir * (1.0 / 3.0 - 0.5), 0.0).xyz + textureLod(source, uv_interp + dir * (2.0 / 3.0 - 0.5), 0.0).xyz);
vec3 rgbB = rgbA * 0.5 + 0.25 * (textureLod(source, uv_interp + dir * -0.5, 0.0).xyz + textureLod(source, uv_interp + dir * 0.5, 0.0).xyz); vec3 rgbB = rgbA * 0.5 + 0.25 * (textureLod(source, uv_interp + dir * -0.5, 0.0).xyz + textureLod(source, uv_interp + dir * 0.5, 0.0).xyz);
#endif
float lumaB = dot(rgbB, luma); float lumaB = dot(rgbB, luma);
if ((lumaB < lumaMin) || (lumaB > lumaMax)) { if ((lumaB < lumaMin) || (lumaB > lumaMax)) {
@ -231,7 +247,11 @@ vec3 apply_fxaa(vec3 color, vec2 uv_interp, vec2 pixel_size) {
} }
void main() { void main() {
#ifdef USE_MULTIVIEW
vec4 color = textureLod(source, vec3(uv_interp, ViewIndex), 0.0);
#else
vec4 color = textureLod(source, uv_interp, 0.0); vec4 color = textureLod(source, uv_interp, 0.0);
#endif
#ifdef USE_FXAA #ifdef USE_FXAA
color.rgb = apply_fxaa(color.rgb, uv_interp, pixel_size); color.rgb = apply_fxaa(color.rgb, uv_interp, pixel_size);

View File

@ -34,6 +34,15 @@
#include "core/config/project_settings.h" #include "core/config/project_settings.h"
#include "core/templates/vector.h" #include "core/templates/vector.h"
#ifdef ANDROID_ENABLED
#include <GLES3/gl3.h>
#include <GLES3/gl3ext.h>
#include <GLES3/gl3platform.h>
#include <EGL/egl.h>
#include <EGL/eglext.h>
#endif
using namespace GLES3; using namespace GLES3;
#define _GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF #define _GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF
@ -98,6 +107,16 @@ Config::Config() {
anisotropic_level = MIN(float(1 << int(ProjectSettings::get_singleton()->get("rendering/textures/default_filters/anisotropic_filtering_level"))), anisotropic_level); anisotropic_level = MIN(float(1 << int(ProjectSettings::get_singleton()->get("rendering/textures/default_filters/anisotropic_filtering_level"))), anisotropic_level);
} }
multiview_supported = extensions.has("GL_OVR_multiview2") || extensions.has("GL_OVR_multiview");
#ifdef ANDROID_ENABLED
if (multiview_supported) {
eglFramebufferTextureMultiviewOVR = (PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC)eglGetProcAddress("glFramebufferTextureMultiviewOVR");
if (eglFramebufferTextureMultiviewOVR == nullptr) {
multiview_supported = false;
}
}
#endif
force_vertex_shading = false; //GLOBAL_GET("rendering/quality/shading/force_vertex_shading"); force_vertex_shading = false; //GLOBAL_GET("rendering/quality/shading/force_vertex_shading");
use_nearest_mip_filter = GLOBAL_GET("rendering/textures/default_filters/use_nearest_mipmap_filter"); use_nearest_mip_filter = GLOBAL_GET("rendering/textures/default_filters/use_nearest_mipmap_filter");

View File

@ -44,6 +44,10 @@
#include OPENGL_INCLUDE_H #include OPENGL_INCLUDE_H
#endif #endif
#ifdef ANDROID_ENABLED
typedef void (*PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC)(GLenum, GLenum, GLuint, GLint, GLint, GLsizei);
#endif
namespace GLES3 { namespace GLES3 {
class Config { class Config {
@ -82,6 +86,11 @@ public:
bool support_anisotropic_filter = false; bool support_anisotropic_filter = false;
float anisotropic_level = 0.0f; float anisotropic_level = 0.0f;
bool multiview_supported = false;
#ifdef ANDROID_ENABLED
PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC eglFramebufferTextureMultiviewOVR = nullptr;
#endif
static Config *get_singleton() { return singleton; }; static Config *get_singleton() { return singleton; };
Config(); Config();

View File

@ -33,12 +33,17 @@
#include "render_scene_buffers_gles3.h" #include "render_scene_buffers_gles3.h"
#include "texture_storage.h" #include "texture_storage.h"
#ifdef ANDROID_ENABLED
#define glFramebufferTextureMultiviewOVR GLES3::Config::get_singleton()->eglFramebufferTextureMultiviewOVR
#endif
RenderSceneBuffersGLES3::~RenderSceneBuffersGLES3() { RenderSceneBuffersGLES3::~RenderSceneBuffersGLES3() {
free_render_buffer_data(); free_render_buffer_data();
} }
void RenderSceneBuffersGLES3::configure(RID p_render_target, const Size2i p_internal_size, const Size2i p_target_size, float p_fsr_sharpness, float p_texture_mipmap_bias, RS::ViewportMSAA p_msaa, RenderingServer::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_taa, bool p_use_debanding, uint32_t p_view_count) { void RenderSceneBuffersGLES3::configure(RID p_render_target, const Size2i p_internal_size, const Size2i p_target_size, float p_fsr_sharpness, float p_texture_mipmap_bias, RS::ViewportMSAA p_msaa, RenderingServer::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_taa, bool p_use_debanding, uint32_t p_view_count) {
GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton(); GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton();
GLES3::Config *config = GLES3::Config::get_singleton();
//internal_size.x = p_internal_size.x; // ignore for now //internal_size.x = p_internal_size.x; // ignore for now
//internal_size.y = p_internal_size.y; //internal_size.y = p_internal_size.y;
@ -50,7 +55,7 @@ void RenderSceneBuffersGLES3::configure(RID p_render_target, const Size2i p_inte
//msaa = p_msaa; //msaa = p_msaa;
//screen_space_aa = p_screen_space_aa; //screen_space_aa = p_screen_space_aa;
//use_debanding = p_use_debanding; //use_debanding = p_use_debanding;
//view_count = p_view_count; view_count = p_view_count;
free_render_buffer_data(); free_render_buffer_data();
@ -62,24 +67,43 @@ void RenderSceneBuffersGLES3::configure(RID p_render_target, const Size2i p_inte
glGenFramebuffers(1, &framebuffer); glGenFramebuffers(1, &framebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
if (view_count > 1 && config->multiview_supported) {
glBindTexture(GL_TEXTURE_2D_ARRAY, rt->color);
glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, rt->color, 0, 0, view_count);
} else {
glBindTexture(GL_TEXTURE_2D, rt->color); glBindTexture(GL_TEXTURE_2D, rt->color);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->color, 0); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->color, 0);
}
glGenTextures(1, &depth_texture); glGenTextures(1, &depth_texture);
glBindTexture(GL_TEXTURE_2D, depth_texture); if (view_count > 1 && config->multiview_supported) {
glBindTexture(GL_TEXTURE_2D_ARRAY, depth_texture);
glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_DEPTH_COMPONENT24, rt->size.x, rt->size.y, view_count, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, nullptr);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
} else {
glBindTexture(GL_TEXTURE_2D, depth_texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, rt->size.x, rt->size.y, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, nullptr); glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, rt->size.x, rt->size.y, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, nullptr);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
}
if (view_count > 1 && config->multiview_supported) {
glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, depth_texture, 0, 0, view_count);
} else {
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depth_texture, 0); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depth_texture, 0);
}
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
glBindTexture(GL_TEXTURE_2D, 0); glBindTexture(GL_TEXTURE_2D, 0);
glBindTexture(GL_TEXTURE_2D_ARRAY, 0);
glBindFramebuffer(GL_FRAMEBUFFER, texture_storage->system_fbo); glBindFramebuffer(GL_FRAMEBUFFER, texture_storage->system_fbo);
if (status != GL_FRAMEBUFFER_COMPLETE) { if (status != GL_FRAMEBUFFER_COMPLETE) {

View File

@ -56,7 +56,7 @@ public:
RS::ViewportMSAA msaa = RS::VIEWPORT_MSAA_DISABLED; RS::ViewportMSAA msaa = RS::VIEWPORT_MSAA_DISABLED;
//RS::ViewportScreenSpaceAA screen_space_aa = RS::VIEWPORT_SCREEN_SPACE_AA_DISABLED; //RS::ViewportScreenSpaceAA screen_space_aa = RS::VIEWPORT_SCREEN_SPACE_AA_DISABLED;
//bool use_debanding = false; //bool use_debanding = false;
//uint32_t view_count = 1; uint32_t view_count = 1;
bool is_transparent = false; bool is_transparent = false;

View File

@ -34,6 +34,10 @@
#include "config.h" #include "config.h"
#include "drivers/gles3/effects/copy_effects.h" #include "drivers/gles3/effects/copy_effects.h"
#ifdef ANDROID_ENABLED
#define glFramebufferTextureMultiviewOVR GLES3::Config::get_singleton()->eglFramebufferTextureMultiviewOVR
#endif
using namespace GLES3; using namespace GLES3;
TextureStorage *TextureStorage::singleton = nullptr; TextureStorage *TextureStorage::singleton = nullptr;
@ -720,8 +724,7 @@ void TextureStorage::texture_proxy_initialize(RID p_texture, RID p_base) {
} }
void TextureStorage::texture_2d_update(RID p_texture, const Ref<Image> &p_image, int p_layer) { void TextureStorage::texture_2d_update(RID p_texture, const Ref<Image> &p_image, int p_layer) {
// only 1 layer so far texture_set_data(p_texture, p_image, p_layer);
texture_set_data(p_texture, p_image);
#ifdef TOOLS_ENABLED #ifdef TOOLS_ENABLED
Texture *tex = texture_owner.get_or_null(p_texture); Texture *tex = texture_owner.get_or_null(p_texture);
@ -1012,7 +1015,7 @@ void TextureStorage::texture_set_data(RID p_texture, const Ref<Image> &p_image,
img->resize_to_po2(false); img->resize_to_po2(false);
} }
GLenum blit_target = (texture->target == GL_TEXTURE_CUBE_MAP) ? _cube_side_enum[p_layer] : GL_TEXTURE_2D; GLenum blit_target = (texture->target == GL_TEXTURE_CUBE_MAP) ? _cube_side_enum[p_layer] : texture->target;
Vector<uint8_t> read = img->get_data(); Vector<uint8_t> read = img->get_data();
@ -1069,8 +1072,12 @@ void TextureStorage::texture_set_data(RID p_texture, const Ref<Image> &p_image,
glCompressedTexImage2D(blit_target, i, internal_format, bw, bh, 0, size, &read[ofs]); glCompressedTexImage2D(blit_target, i, internal_format, bw, bh, 0, size, &read[ofs]);
} else { } else {
glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
if (texture->target == GL_TEXTURE_2D_ARRAY) {
glTexSubImage3D(GL_TEXTURE_2D_ARRAY, i, 0, 0, p_layer, w, h, 0, format, type, &read[ofs]);
} else {
glTexImage2D(blit_target, i, internal_format, w, h, 0, format, type, &read[ofs]); glTexImage2D(blit_target, i, internal_format, w, h, 0, format, type, &read[ofs]);
} }
}
tsize += size; tsize += size;
@ -1425,6 +1432,8 @@ void TextureStorage::_update_render_target(RenderTarget *rt) {
return; return;
} }
Config *config = Config::get_singleton();
rt->color_internal_format = rt->is_transparent ? GL_RGBA8 : GL_RGB10_A2; rt->color_internal_format = rt->is_transparent ? GL_RGBA8 : GL_RGB10_A2;
rt->color_format = GL_RGBA; rt->color_format = GL_RGBA;
rt->color_type = rt->is_transparent ? GL_UNSIGNED_BYTE : GL_UNSIGNED_INT_2_10_10_10_REV; rt->color_type = rt->is_transparent ? GL_UNSIGNED_BYTE : GL_UNSIGNED_INT_2_10_10_10_REV;
@ -1446,17 +1455,29 @@ void TextureStorage::_update_render_target(RenderTarget *rt) {
// color // color
glGenTextures(1, &rt->color); glGenTextures(1, &rt->color);
glBindTexture(GL_TEXTURE_2D, rt->color); if (rt->view_count > 1 && config->multiview_supported) {
glBindTexture(GL_TEXTURE_2D_ARRAY, rt->color);
glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, rt->color_internal_format, rt->size.x, rt->size.y, rt->view_count, 0, rt->color_format, rt->color_type, nullptr);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
} else {
glBindTexture(GL_TEXTURE_2D, rt->color);
glTexImage2D(GL_TEXTURE_2D, 0, rt->color_internal_format, rt->size.x, rt->size.y, 0, rt->color_format, rt->color_type, nullptr); glTexImage2D(GL_TEXTURE_2D, 0, rt->color_internal_format, rt->size.x, rt->size.y, 0, rt->color_format, rt->color_type, nullptr);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
}
if (rt->view_count > 1 && config->multiview_supported) {
glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, rt->color, 0, 0, rt->view_count);
} else {
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->color, 0); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->color, 0);
}
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
@ -1475,8 +1496,15 @@ void TextureStorage::_update_render_target(RenderTarget *rt) {
texture->format = rt->image_format; texture->format = rt->image_format;
texture->real_format = rt->image_format; texture->real_format = rt->image_format;
if (rt->view_count > 1 && config->multiview_supported) {
texture->type = Texture::TYPE_LAYERED;
texture->target = GL_TEXTURE_2D_ARRAY;
texture->layers = rt->view_count;
} else {
texture->type = Texture::TYPE_2D; texture->type = Texture::TYPE_2D;
texture->target = GL_TEXTURE_2D; texture->target = GL_TEXTURE_2D;
texture->layers = 1;
}
texture->gl_format_cache = rt->color_format; texture->gl_format_cache = rt->color_format;
texture->gl_type_cache = GL_UNSIGNED_BYTE; texture->gl_type_cache = GL_UNSIGNED_BYTE;
texture->gl_internal_format_cache = rt->color_internal_format; texture->gl_internal_format_cache = rt->color_internal_format;
@ -1619,13 +1647,14 @@ void TextureStorage::render_target_set_size(RID p_render_target, int p_width, in
RenderTarget *rt = render_target_owner.get_or_null(p_render_target); RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
ERR_FAIL_COND(!rt); ERR_FAIL_COND(!rt);
if (p_width == rt->size.x && p_height == rt->size.y) { if (p_width == rt->size.x && p_height == rt->size.y && p_view_count == rt->view_count) {
return; return;
} }
_clear_render_target(rt); _clear_render_target(rt);
rt->size = Size2i(p_width, p_height); rt->size = Size2i(p_width, p_height);
rt->view_count = p_view_count;
_update_render_target(rt); _update_render_target(rt);
} }

View File

@ -324,6 +324,7 @@ private:
struct RenderTarget { struct RenderTarget {
Point2i position = Point2i(0, 0); Point2i position = Point2i(0, 0);
Size2i size = Size2i(0, 0); Size2i size = Size2i(0, 0);
uint32_t view_count = 1;
int mipmap_count = 1; int mipmap_count = 1;
RID self; RID self;
GLuint fbo = 0; GLuint fbo = 0;

View File

@ -65,7 +65,7 @@ extern int godot_webxr_get_view_count();
extern int *godot_webxr_get_render_target_size(); extern int *godot_webxr_get_render_target_size();
extern float *godot_webxr_get_transform_for_eye(int p_eye); extern float *godot_webxr_get_transform_for_eye(int p_eye);
extern float *godot_webxr_get_projection_for_eye(int p_eye); extern float *godot_webxr_get_projection_for_eye(int p_eye);
extern void godot_webxr_commit_for_eye(int p_eye, unsigned int p_destination_fbo); extern void godot_webxr_commit(unsigned int p_texture);
extern void godot_webxr_sample_controller_data(); extern void godot_webxr_sample_controller_data();
extern int godot_webxr_get_controller_count(); extern int godot_webxr_get_controller_count();

View File

@ -337,20 +337,18 @@ const GodotWebXR = {
return buf; return buf;
}, },
godot_webxr_commit_for_eye__proxy: 'sync', godot_webxr_commit__proxy: 'sync',
godot_webxr_commit_for_eye__sig: 'vii', godot_webxr_commit__sig: 'vi',
godot_webxr_commit_for_eye: function (p_eye, p_destination_fbo) { godot_webxr_commit: function (p_texture) {
if (!GodotWebXR.session || !GodotWebXR.pose) { if (!GodotWebXR.session || !GodotWebXR.pose) {
return; return;
} }
const view_index = (p_eye === 2 /* ARVRInterface::EYE_RIGHT */) ? 1 : 0;
const glLayer = GodotWebXR.session.renderState.baseLayer; const glLayer = GodotWebXR.session.renderState.baseLayer;
const view = GodotWebXR.pose.views[view_index]; const views = GodotWebXR.pose.views;
const viewport = glLayer.getViewport(view);
const gl = GodotWebXR.gl; const gl = GodotWebXR.gl;
const framebuffer = GL.framebuffers[p_destination_fbo]; const texture = GL.textures[p_texture];
const orig_framebuffer = gl.getParameter(gl.FRAMEBUFFER_BINDING); const orig_framebuffer = gl.getParameter(gl.FRAMEBUFFER_BINDING);
const orig_read_framebuffer = gl.getParameter(gl.READ_FRAMEBUFFER_BINDING); const orig_read_framebuffer = gl.getParameter(gl.READ_FRAMEBUFFER_BINDING);
@ -359,15 +357,28 @@ const GodotWebXR = {
// Copy from Godot render target into framebuffer from WebXR. // Copy from Godot render target into framebuffer from WebXR.
gl.bindFramebuffer(gl.FRAMEBUFFER, null); gl.bindFramebuffer(gl.FRAMEBUFFER, null);
gl.bindFramebuffer(gl.READ_FRAMEBUFFER, framebuffer); for (let i = 0; i < views.length; i++) {
const viewport = glLayer.getViewport(views[i]);
const read_fbo = gl.createFramebuffer();
gl.bindFramebuffer(gl.READ_FRAMEBUFFER, read_fbo);
if (views.length > 1) {
gl.framebufferTextureLayer(gl.READ_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, texture, 0, i);
} else {
gl.framebufferTexture2D(gl.READ_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0);
}
gl.readBuffer(gl.COLOR_ATTACHMENT0); gl.readBuffer(gl.COLOR_ATTACHMENT0);
gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, glLayer.framebuffer); gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, glLayer.framebuffer);
// Flip Y upside down on destination. // Flip Y upside down on destination.
gl.blitFramebuffer(0, 0, viewport.width, viewport.height, gl.blitFramebuffer(0, 0, viewport.width, viewport.height,
viewport.x, viewport.height, viewport.width, viewport.y, viewport.x, viewport.y + viewport.height, viewport.x + viewport.width, viewport.y,
gl.COLOR_BUFFER_BIT, gl.NEAREST); gl.COLOR_BUFFER_BIT, gl.NEAREST);
gl.bindFramebuffer(gl.READ_FRAMEBUFFER, null);
gl.deleteFramebuffer(read_fbo);
}
// Restore state. // Restore state.
gl.bindFramebuffer(gl.FRAMEBUFFER, orig_framebuffer); gl.bindFramebuffer(gl.FRAMEBUFFER, orig_framebuffer);
gl.bindFramebuffer(gl.READ_FRAMEBUFFER, orig_read_framebuffer); gl.bindFramebuffer(gl.READ_FRAMEBUFFER, orig_read_framebuffer);

View File

@ -415,8 +415,7 @@ Vector<BlitToScreen> WebXRInterfaceJS::post_draw_viewport(RID p_render_target, c
GLES3::RenderTarget *rt = texture_storage->get_render_target(p_render_target); GLES3::RenderTarget *rt = texture_storage->get_render_target(p_render_target);
// @todo Support multiple eyes! godot_webxr_commit(rt->color);
godot_webxr_commit_for_eye(1, rt->fbo);
return blit_to_screen; return blit_to_screen;
}; };

View File

@ -35,6 +35,7 @@ sys_env.AddJSLibraries(
"js/libs/library_godot_os.js", "js/libs/library_godot_os.js",
"js/libs/library_godot_runtime.js", "js/libs/library_godot_runtime.js",
"js/libs/library_godot_input.js", "js/libs/library_godot_input.js",
"js/libs/library_godot_webgl2.js",
] ]
) )

View File

@ -773,6 +773,9 @@ DisplayServerWeb::DisplayServerWeb(const String &p_rendering_driver, WindowMode
if (emscripten_webgl_make_context_current(webgl_ctx) != EMSCRIPTEN_RESULT_SUCCESS) { if (emscripten_webgl_make_context_current(webgl_ctx) != EMSCRIPTEN_RESULT_SUCCESS) {
webgl2_init_failed = true; webgl2_init_failed = true;
} else { } else {
if (!emscripten_webgl_enable_extension(webgl_ctx, "OVR_multiview2")) {
// @todo Should we log this?
}
RasterizerGLES3::make_current(); RasterizerGLES3::make_current();
} }
} }

View File

@ -34,4 +34,21 @@
#include "GLES3/gl3.h" #include "GLES3/gl3.h"
#include "webgl/webgl2.h" #include "webgl/webgl2.h"
#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_NUM_VIEWS_OVR 0x9630
#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_BASE_VIEW_INDEX_OVR 0x9632
#define GL_MAX_VIEWS_OVR 0x9631
#define GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_OVR 0x9633
#ifdef __cplusplus
extern "C" {
#endif
void godot_webgl2_glFramebufferTextureMultiviewOVR(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint baseViewIndex, GLsizei numViews);
#define glFramebufferTextureMultiviewOVR godot_webgl2_glFramebufferTextureMultiviewOVR
#ifdef __cplusplus
}
#endif
#endif // GODOT_WEBGL2_H #endif // GODOT_WEBGL2_H

View File

@ -0,0 +1,52 @@
/*************************************************************************/
/* library_godot_webgl2.js */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
const GodotWebGL2 = {
$GodotWebGL2__deps: ['$GL', '$GodotRuntime'],
$GodotWebGL2: {},
godot_webgl2_glFramebufferTextureMultiviewOVR__deps: ['emscripten_webgl_get_current_context'],
godot_webgl2_glFramebufferTextureMultiviewOVR__proxy: 'sync',
godot_webgl2_glFramebufferTextureMultiviewOVR__sig: 'viiiiii',
godot_webgl2_glFramebufferTextureMultiviewOVR: function (target, attachment, texture, level, base_view_index, num_views) {
const context = GL.currentContext;
if (typeof context.multiviewExt === 'undefined') {
const ext = context.GLctx.getExtension('OVR_multiview2');
if (!ext) {
console.error('Trying to call glFramebufferTextureMultiviewOVR() without the OVR_multiview2 extension');
return;
}
context.multiviewExt = ext;
}
context.multiviewExt.framebufferTextureMultiviewOVR(target, attachment, GL.textures[texture], level, base_view_index, num_views);
},
};
autoAddDeps(GodotWebGL2, '$GodotWebGL2');
mergeInto(LibraryManager.library, GodotWebGL2);

View File

@ -153,6 +153,20 @@ typedef int64_t khronos_int64_t;
typedef uint64_t khronos_uint64_t; typedef uint64_t khronos_uint64_t;
#define KHRONOS_SUPPORT_INT64 1 #define KHRONOS_SUPPORT_INT64 1
#define KHRONOS_SUPPORT_FLOAT 1 #define KHRONOS_SUPPORT_FLOAT 1
/*
* To support platform where unsigned long cannot be used interchangeably with
* inptr_t (e.g. CHERI-extended ISAs), we can use the stdint.h intptr_t.
* Ideally, we could just use (u)intptr_t everywhere, but this could result in
* ABI breakage if khronos_uintptr_t is changed from unsigned long to
* unsigned long long or similar (this results in different C++ name mangling).
* To avoid changes for existing platforms, we restrict usage of intptr_t to
* platforms where the size of a pointer is larger than the size of long.
*/
#if defined(__SIZEOF_LONG__) && defined(__SIZEOF_POINTER__)
#if __SIZEOF_POINTER__ > __SIZEOF_LONG__
#define KHRONOS_USE_INTPTR_T
#endif
#endif
#elif defined(__VMS ) || defined(__sgi) #elif defined(__VMS ) || defined(__sgi)
@ -235,14 +249,21 @@ typedef unsigned short int khronos_uint16_t;
* pointers are 64 bits, but 'long' is still 32 bits. Win64 appears * pointers are 64 bits, but 'long' is still 32 bits. Win64 appears
* to be the only LLP64 architecture in current use. * to be the only LLP64 architecture in current use.
*/ */
#ifdef _WIN64 #ifdef KHRONOS_USE_INTPTR_T
typedef intptr_t khronos_intptr_t;
typedef uintptr_t khronos_uintptr_t;
#elif defined(_WIN64)
typedef signed long long int khronos_intptr_t; typedef signed long long int khronos_intptr_t;
typedef unsigned long long int khronos_uintptr_t; typedef unsigned long long int khronos_uintptr_t;
typedef signed long long int khronos_ssize_t;
typedef unsigned long long int khronos_usize_t;
#else #else
typedef signed long int khronos_intptr_t; typedef signed long int khronos_intptr_t;
typedef unsigned long int khronos_uintptr_t; typedef unsigned long int khronos_uintptr_t;
#endif
#if defined(_WIN64)
typedef signed long long int khronos_ssize_t;
typedef unsigned long long int khronos_usize_t;
#else
typedef signed long int khronos_ssize_t; typedef signed long int khronos_ssize_t;
typedef unsigned long int khronos_usize_t; typedef unsigned long int khronos_usize_t;
#endif #endif

View File

@ -1,6 +1,6 @@
/* /*
OpenGL loader generated by glad 0.1.34 on Tue Nov 17 16:41:02 2020. OpenGL loader generated by glad 0.1.36 on Sun Sep 4 15:50:32 2022.
Language/Generator: C/C++ Language/Generator: C/C++
Specification: gl Specification: gl
@ -11,16 +11,18 @@
GL_ARB_framebuffer_object, GL_ARB_framebuffer_object,
GL_EXT_framebuffer_blit, GL_EXT_framebuffer_blit,
GL_EXT_framebuffer_multisample, GL_EXT_framebuffer_multisample,
GL_EXT_framebuffer_object GL_EXT_framebuffer_object,
GL_OVR_multiview,
GL_OVR_multiview2
Loader: True Loader: True
Local files: False Local files: False
Omit khrplatform: False Omit khrplatform: False
Reproducible: False Reproducible: False
Commandline: Commandline:
--profile="compatibility" --api="gl=3.3" --generator="c" --spec="gl" --extensions="GL_ARB_debug_output,GL_ARB_framebuffer_object,GL_EXT_framebuffer_blit,GL_EXT_framebuffer_multisample,GL_EXT_framebuffer_object" --profile="compatibility" --api="gl=3.3" --generator="c" --spec="gl" --extensions="GL_ARB_debug_output,GL_ARB_framebuffer_object,GL_EXT_framebuffer_blit,GL_EXT_framebuffer_multisample,GL_EXT_framebuffer_object,GL_OVR_multiview,GL_OVR_multiview2"
Online: Online:
https://glad.dav1d.de/#profile=compatibility&language=c&specification=gl&loader=on&api=gl%3D3.3&extensions=GL_ARB_debug_output&extensions=GL_ARB_framebuffer_object&extensions=GL_EXT_framebuffer_blit&extensions=GL_EXT_framebuffer_multisample&extensions=GL_EXT_framebuffer_object https://glad.dav1d.de/#profile=compatibility&language=c&specification=gl&loader=on&api=gl%3D3.3&extensions=GL_ARB_debug_output&extensions=GL_ARB_framebuffer_object&extensions=GL_EXT_framebuffer_blit&extensions=GL_EXT_framebuffer_multisample&extensions=GL_EXT_framebuffer_object&extensions=GL_OVR_multiview&extensions=GL_OVR_multiview2
*/ */
#include <stdio.h> #include <stdio.h>
@ -1000,6 +1002,8 @@ int GLAD_GL_ARB_framebuffer_object = 0;
int GLAD_GL_EXT_framebuffer_blit = 0; int GLAD_GL_EXT_framebuffer_blit = 0;
int GLAD_GL_EXT_framebuffer_multisample = 0; int GLAD_GL_EXT_framebuffer_multisample = 0;
int GLAD_GL_EXT_framebuffer_object = 0; int GLAD_GL_EXT_framebuffer_object = 0;
int GLAD_GL_OVR_multiview = 0;
int GLAD_GL_OVR_multiview2 = 0;
PFNGLDEBUGMESSAGECONTROLARBPROC glad_glDebugMessageControlARB = NULL; PFNGLDEBUGMESSAGECONTROLARBPROC glad_glDebugMessageControlARB = NULL;
PFNGLDEBUGMESSAGEINSERTARBPROC glad_glDebugMessageInsertARB = NULL; PFNGLDEBUGMESSAGEINSERTARBPROC glad_glDebugMessageInsertARB = NULL;
PFNGLDEBUGMESSAGECALLBACKARBPROC glad_glDebugMessageCallbackARB = NULL; PFNGLDEBUGMESSAGECALLBACKARBPROC glad_glDebugMessageCallbackARB = NULL;
@ -1023,6 +1027,7 @@ PFNGLFRAMEBUFFERTEXTURE3DEXTPROC glad_glFramebufferTexture3DEXT = NULL;
PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC glad_glFramebufferRenderbufferEXT = NULL; PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC glad_glFramebufferRenderbufferEXT = NULL;
PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC glad_glGetFramebufferAttachmentParameterivEXT = NULL; PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC glad_glGetFramebufferAttachmentParameterivEXT = NULL;
PFNGLGENERATEMIPMAPEXTPROC glad_glGenerateMipmapEXT = NULL; PFNGLGENERATEMIPMAPEXTPROC glad_glGenerateMipmapEXT = NULL;
PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC glad_glFramebufferTextureMultiviewOVR = NULL;
static void load_GL_VERSION_1_0(GLADloadproc load) { static void load_GL_VERSION_1_0(GLADloadproc load) {
if(!GLAD_GL_VERSION_1_0) return; if(!GLAD_GL_VERSION_1_0) return;
glad_glCullFace = (PFNGLCULLFACEPROC)load("glCullFace"); glad_glCullFace = (PFNGLCULLFACEPROC)load("glCullFace");
@ -1844,6 +1849,10 @@ static void load_GL_EXT_framebuffer_object(GLADloadproc load) {
glad_glGetFramebufferAttachmentParameterivEXT = (PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC)load("glGetFramebufferAttachmentParameterivEXT"); glad_glGetFramebufferAttachmentParameterivEXT = (PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC)load("glGetFramebufferAttachmentParameterivEXT");
glad_glGenerateMipmapEXT = (PFNGLGENERATEMIPMAPEXTPROC)load("glGenerateMipmapEXT"); glad_glGenerateMipmapEXT = (PFNGLGENERATEMIPMAPEXTPROC)load("glGenerateMipmapEXT");
} }
static void load_GL_OVR_multiview(GLADloadproc load) {
if(!GLAD_GL_OVR_multiview) return;
glad_glFramebufferTextureMultiviewOVR = (PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC)load("glFramebufferTextureMultiviewOVR");
}
static int find_extensionsGL(void) { static int find_extensionsGL(void) {
if (!get_exts()) return 0; if (!get_exts()) return 0;
GLAD_GL_ARB_debug_output = has_ext("GL_ARB_debug_output"); GLAD_GL_ARB_debug_output = has_ext("GL_ARB_debug_output");
@ -1851,6 +1860,8 @@ static int find_extensionsGL(void) {
GLAD_GL_EXT_framebuffer_blit = has_ext("GL_EXT_framebuffer_blit"); GLAD_GL_EXT_framebuffer_blit = has_ext("GL_EXT_framebuffer_blit");
GLAD_GL_EXT_framebuffer_multisample = has_ext("GL_EXT_framebuffer_multisample"); GLAD_GL_EXT_framebuffer_multisample = has_ext("GL_EXT_framebuffer_multisample");
GLAD_GL_EXT_framebuffer_object = has_ext("GL_EXT_framebuffer_object"); GLAD_GL_EXT_framebuffer_object = has_ext("GL_EXT_framebuffer_object");
GLAD_GL_OVR_multiview = has_ext("GL_OVR_multiview");
GLAD_GL_OVR_multiview2 = has_ext("GL_OVR_multiview2");
free_exts(); free_exts();
return 1; return 1;
} }
@ -1934,6 +1945,7 @@ int gladLoadGLLoader(GLADloadproc load) {
load_GL_EXT_framebuffer_blit(load); load_GL_EXT_framebuffer_blit(load);
load_GL_EXT_framebuffer_multisample(load); load_GL_EXT_framebuffer_multisample(load);
load_GL_EXT_framebuffer_object(load); load_GL_EXT_framebuffer_object(load);
load_GL_OVR_multiview(load);
return GLVersion.major != 0 || GLVersion.minor != 0; return GLVersion.major != 0 || GLVersion.minor != 0;
} }

View File

@ -1,6 +1,6 @@
/* /*
OpenGL loader generated by glad 0.1.34 on Tue Nov 17 16:41:02 2020. OpenGL loader generated by glad 0.1.36 on Sun Sep 4 15:50:32 2022.
Language/Generator: C/C++ Language/Generator: C/C++
Specification: gl Specification: gl
@ -11,16 +11,18 @@
GL_ARB_framebuffer_object, GL_ARB_framebuffer_object,
GL_EXT_framebuffer_blit, GL_EXT_framebuffer_blit,
GL_EXT_framebuffer_multisample, GL_EXT_framebuffer_multisample,
GL_EXT_framebuffer_object GL_EXT_framebuffer_object,
GL_OVR_multiview,
GL_OVR_multiview2
Loader: True Loader: True
Local files: False Local files: False
Omit khrplatform: False Omit khrplatform: False
Reproducible: False Reproducible: False
Commandline: Commandline:
--profile="compatibility" --api="gl=3.3" --generator="c" --spec="gl" --extensions="GL_ARB_debug_output,GL_ARB_framebuffer_object,GL_EXT_framebuffer_blit,GL_EXT_framebuffer_multisample,GL_EXT_framebuffer_object" --profile="compatibility" --api="gl=3.3" --generator="c" --spec="gl" --extensions="GL_ARB_debug_output,GL_ARB_framebuffer_object,GL_EXT_framebuffer_blit,GL_EXT_framebuffer_multisample,GL_EXT_framebuffer_object,GL_OVR_multiview,GL_OVR_multiview2"
Online: Online:
https://glad.dav1d.de/#profile=compatibility&language=c&specification=gl&loader=on&api=gl%3D3.3&extensions=GL_ARB_debug_output&extensions=GL_ARB_framebuffer_object&extensions=GL_EXT_framebuffer_blit&extensions=GL_EXT_framebuffer_multisample&extensions=GL_EXT_framebuffer_object https://glad.dav1d.de/#profile=compatibility&language=c&specification=gl&loader=on&api=gl%3D3.3&extensions=GL_ARB_debug_output&extensions=GL_ARB_framebuffer_object&extensions=GL_EXT_framebuffer_blit&extensions=GL_EXT_framebuffer_multisample&extensions=GL_EXT_framebuffer_object&extensions=GL_OVR_multiview&extensions=GL_OVR_multiview2
*/ */
@ -3687,6 +3689,10 @@ GLAPI PFNGLSECONDARYCOLORP3UIVPROC glad_glSecondaryColorP3uiv;
#define GL_RENDERBUFFER_ALPHA_SIZE_EXT 0x8D53 #define GL_RENDERBUFFER_ALPHA_SIZE_EXT 0x8D53
#define GL_RENDERBUFFER_DEPTH_SIZE_EXT 0x8D54 #define GL_RENDERBUFFER_DEPTH_SIZE_EXT 0x8D54
#define GL_RENDERBUFFER_STENCIL_SIZE_EXT 0x8D55 #define GL_RENDERBUFFER_STENCIL_SIZE_EXT 0x8D55
#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_NUM_VIEWS_OVR 0x9630
#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_BASE_VIEW_INDEX_OVR 0x9632
#define GL_MAX_VIEWS_OVR 0x9631
#define GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_OVR 0x9633
#ifndef GL_ARB_debug_output #ifndef GL_ARB_debug_output
#define GL_ARB_debug_output 1 #define GL_ARB_debug_output 1
GLAPI int GLAD_GL_ARB_debug_output; GLAPI int GLAD_GL_ARB_debug_output;
@ -3776,6 +3782,17 @@ typedef void (APIENTRYP PFNGLGENERATEMIPMAPEXTPROC)(GLenum target);
GLAPI PFNGLGENERATEMIPMAPEXTPROC glad_glGenerateMipmapEXT; GLAPI PFNGLGENERATEMIPMAPEXTPROC glad_glGenerateMipmapEXT;
#define glGenerateMipmapEXT glad_glGenerateMipmapEXT #define glGenerateMipmapEXT glad_glGenerateMipmapEXT
#endif #endif
#ifndef GL_OVR_multiview
#define GL_OVR_multiview 1
GLAPI int GLAD_GL_OVR_multiview;
typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC)(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint baseViewIndex, GLsizei numViews);
GLAPI PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC glad_glFramebufferTextureMultiviewOVR;
#define glFramebufferTextureMultiviewOVR glad_glFramebufferTextureMultiviewOVR
#endif
#ifndef GL_OVR_multiview2
#define GL_OVR_multiview2 1
GLAPI int GLAD_GL_OVR_multiview2;
#endif
#ifdef __cplusplus #ifdef __cplusplus
} }