diff options
Diffstat (limited to 'drivers')
68 files changed, 10527 insertions, 27595 deletions
diff --git a/drivers/SCsub b/drivers/SCsub index d91d98a713..932014b540 100644 --- a/drivers/SCsub +++ b/drivers/SCsub @@ -24,14 +24,15 @@ SConscript('winmidi/SCsub') # Graphics drivers if (env["platform"] != "server"): - SConscript('gles3/SCsub') - SConscript('gles2/SCsub') +# SConscript('gles2/SCsub') + SConscript('vulkan/SCsub') SConscript('gl_context/SCsub') else: SConscript('dummy/SCsub') # Core dependencies SConscript("png/SCsub") +SConscript("spirv-reflect/SCsub") if env['vsproj']: import os diff --git a/drivers/alsa/audio_driver_alsa.cpp b/drivers/alsa/audio_driver_alsa.cpp index 425f12ae91..fe6cd091b7 100644 --- a/drivers/alsa/audio_driver_alsa.cpp +++ b/drivers/alsa/audio_driver_alsa.cpp @@ -204,7 +204,7 @@ void AudioDriverALSA::thread_func(void *p_udata) { } else { wrote = snd_pcm_recover(ad->pcm_handle, wrote, 0); if (wrote < 0) { - ERR_PRINTS("ALSA: Failed and can't recover: " + String(snd_strerror(wrote))); + ERR_PRINT("ALSA: Failed and can't recover: " + String(snd_strerror(wrote))); ad->active = false; ad->exit_thread = true; } diff --git a/drivers/alsamidi/midi_driver_alsamidi.cpp b/drivers/alsamidi/midi_driver_alsamidi.cpp index 68a34fe485..6121a44b36 100644 --- a/drivers/alsamidi/midi_driver_alsamidi.cpp +++ b/drivers/alsamidi/midi_driver_alsamidi.cpp @@ -91,7 +91,7 @@ void MIDIDriverALSAMidi::thread_func(void *p_udata) { ret = snd_rawmidi_read(midi_in, &byte, 1); if (ret < 0) { if (ret != -EAGAIN) { - ERR_PRINTS("snd_rawmidi_read error: " + String(snd_strerror(ret))); + ERR_PRINT("snd_rawmidi_read error: " + String(snd_strerror(ret))); } } else { if (byte & 0x80) { diff --git a/drivers/coreaudio/audio_driver_coreaudio.cpp b/drivers/coreaudio/audio_driver_coreaudio.cpp index c67e90c1df..d8229f7bf2 100644 --- a/drivers/coreaudio/audio_driver_coreaudio.cpp +++ b/drivers/coreaudio/audio_driver_coreaudio.cpp @@ -241,7 +241,7 @@ OSStatus AudioDriverCoreAudio::input_callback(void *inRefCon, } } } else { - ERR_PRINTS("AudioUnitRender failed, code: " + itos(result)); + ERR_PRINT("AudioUnitRender failed, code: " + itos(result)); } ad->unlock(); @@ -253,7 +253,7 @@ void AudioDriverCoreAudio::start() { if (!active) { OSStatus result = AudioOutputUnitStart(audio_unit); if (result != noErr) { - ERR_PRINTS("AudioOutputUnitStart failed, code: " + itos(result)); + ERR_PRINT("AudioOutputUnitStart failed, code: " + itos(result)); } else { active = true; } @@ -264,7 +264,7 @@ void AudioDriverCoreAudio::stop() { if (active) { OSStatus result = AudioOutputUnitStop(audio_unit); if (result != noErr) { - ERR_PRINTS("AudioOutputUnitStop failed, code: " + itos(result)); + ERR_PRINT("AudioOutputUnitStop failed, code: " + itos(result)); } else { active = false; } @@ -491,7 +491,7 @@ Error AudioDriverCoreAudio::capture_start() { OSStatus result = AudioOutputUnitStart(input_unit); if (result != noErr) { - ERR_PRINTS("AudioOutputUnitStart failed, code: " + itos(result)); + ERR_PRINT("AudioOutputUnitStart failed, code: " + itos(result)); } return OK; @@ -502,7 +502,7 @@ Error AudioDriverCoreAudio::capture_stop() { if (input_unit) { OSStatus result = AudioOutputUnitStop(input_unit); if (result != noErr) { - ERR_PRINTS("AudioOutputUnitStop failed, code: " + itos(result)); + ERR_PRINT("AudioOutputUnitStop failed, code: " + itos(result)); } } diff --git a/drivers/coremidi/midi_driver_coremidi.cpp b/drivers/coremidi/midi_driver_coremidi.cpp index 06082a9140..99628c7fe3 100644 --- a/drivers/coremidi/midi_driver_coremidi.cpp +++ b/drivers/coremidi/midi_driver_coremidi.cpp @@ -51,13 +51,13 @@ Error MIDIDriverCoreMidi::open() { OSStatus result = MIDIClientCreate(name, NULL, NULL, &client); CFRelease(name); if (result != noErr) { - ERR_PRINTS("MIDIClientCreate failed, code: " + itos(result)); + ERR_PRINT("MIDIClientCreate failed, code: " + itos(result)); return ERR_CANT_OPEN; } result = MIDIInputPortCreate(client, CFSTR("Godot Input"), MIDIDriverCoreMidi::read, (void *)this, &port_in); if (result != noErr) { - ERR_PRINTS("MIDIInputPortCreate failed, code: " + itos(result)); + ERR_PRINT("MIDIInputPortCreate failed, code: " + itos(result)); return ERR_CANT_OPEN; } diff --git a/drivers/dummy/rasterizer_dummy.h b/drivers/dummy/rasterizer_dummy.h index 00758a73a4..990a0dc455 100644 --- a/drivers/dummy/rasterizer_dummy.h +++ b/drivers/dummy/rasterizer_dummy.h @@ -32,6 +32,7 @@ #define RASTERIZER_DUMMY_H #include "core/math/camera_matrix.h" +#include "core/rid_owner.h" #include "core/self_list.h" #include "scene/resources/mesh.h" #include "servers/visual/rasterizer.h" @@ -121,7 +122,7 @@ public: class RasterizerStorageDummy : public RasterizerStorage { public: /* TEXTURE API */ - struct DummyTexture : public RID_Data { + struct DummyTexture { int width; int height; uint32_t flags; @@ -142,14 +143,14 @@ public: Vector<AABB> bone_aabbs; }; - struct DummyMesh : public RID_Data { + struct DummyMesh { Vector<DummySurface> surfaces; int blend_shape_count; VS::BlendShapeMode blend_shape_mode; }; - mutable RID_Owner<DummyTexture> texture_owner; - mutable RID_Owner<DummyMesh> mesh_owner; + mutable RID_PtrOwner<DummyTexture> texture_owner; + mutable RID_PtrOwner<DummyMesh> mesh_owner; RID texture_create() { @@ -178,7 +179,7 @@ public: } void texture_set_data_partial(RID p_texture, const Ref<Image> &p_image, int src_x, int src_y, int src_w, int src_h, int dst_x, int dst_y, int p_dst_mip, int p_level) { - DummyTexture *t = texture_owner.get(p_texture); + DummyTexture *t = texture_owner.getornull(p_texture); ERR_FAIL_COND(!t); ERR_FAIL_COND_MSG(p_image.is_null(), "It's not a reference to a valid Image object."); @@ -588,7 +589,7 @@ public: void gi_probe_dynamic_data_update(RID p_gi_probe_data, int p_depth_slice, int p_slice_count, int p_mipmap, const void *p_data) {} /* LIGHTMAP CAPTURE */ - struct Instantiable : public RID_Data { + struct Instantiable { SelfList<RasterizerScene::InstanceBase>::List instance_list; @@ -630,7 +631,7 @@ public: } }; - mutable RID_Owner<LightmapCapture> lightmap_capture_data_owner; + mutable RID_PtrOwner<LightmapCapture> lightmap_capture_data_owner; void lightmap_capture_set_bounds(RID p_capture, const AABB &p_bounds) {} AABB lightmap_capture_get_bounds(RID p_capture) const { return AABB(); } void lightmap_capture_set_octree(RID p_capture, const PoolVector<uint8_t> &p_octree) {} @@ -700,7 +701,7 @@ public: void render_target_set_external_texture(RID p_render_target, unsigned int p_texture_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) {} + void render_target_set_as_unused(RID p_render_target) {} void render_target_set_msaa(RID p_render_target, VS::ViewportMSAA p_msaa) {} /* CANVAS SHADOW */ @@ -724,7 +725,7 @@ public: if (texture_owner.owns(p_rid)) { // delete the texture - DummyTexture *texture = texture_owner.get(p_rid); + DummyTexture *texture = texture_owner.getornull(p_rid); texture_owner.free(p_rid); memdelete(texture); } @@ -793,7 +794,7 @@ public: void clear_render_target(const Color &p_color) {} void blit_render_target_to_screen(RID p_render_target, const Rect2 &p_screen_rect, int p_screen = 0) {} void output_lens_distorted_to_screen(RID p_render_target, const Rect2 &p_screen_rect, float p_k1, float p_k2, const Vector2 &p_eye_center, float p_oversample) {} - void end_frame(bool p_swap_buffers) {} + void end_frame(bool p_swap_buffers) { OS::get_singleton()->swap_buffers(); } void finalize() {} static Error is_viable() { diff --git a/drivers/dummy/texture_loader_dummy.cpp b/drivers/dummy/texture_loader_dummy.cpp index 2dfc0afe78..bf51d76527 100644 --- a/drivers/dummy/texture_loader_dummy.cpp +++ b/drivers/dummy/texture_loader_dummy.cpp @@ -74,7 +74,7 @@ void ResourceFormatDummyTexture::get_recognized_extensions(List<String> *p_exten } bool ResourceFormatDummyTexture::handles_type(const String &p_type) const { - return ClassDB::is_parent_class(p_type, "Texture"); + return ClassDB::is_parent_class(p_type, "Texture2D"); } String ResourceFormatDummyTexture::get_resource_type(const String &p_path) const { diff --git a/drivers/gles2/rasterizer_canvas_gles2.cpp b/drivers/gles2/rasterizer_canvas_gles2.cpp index 373d3989ce..24927c4bb8 100644 --- a/drivers/gles2/rasterizer_canvas_gles2.cpp +++ b/drivers/gles2/rasterizer_canvas_gles2.cpp @@ -88,7 +88,7 @@ void RasterizerCanvasGLES2::_set_uniforms() { state.canvas_shader.set_uniform(CanvasShaderGLES2::LIGHT_OUTSIDE_ALPHA, light->mode == VS::CANVAS_LIGHT_MODE_MASK ? 1.0 : 0.0); if (state.using_shadow) { - RasterizerStorageGLES2::CanvasLightShadow *cls = storage->canvas_light_shadow_owner.get(light->shadow_buffer); + RasterizerStorageGLES2::CanvasLightShadow *cls = storage->canvas_light_shadow_owner.getornull(light->shadow_buffer); glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 5); glBindTexture(GL_TEXTURE_2D, cls->distance); state.canvas_shader.set_uniform(CanvasShaderGLES2::SHADOW_MATRIX, light->shadow_matrix_cache); @@ -1033,11 +1033,11 @@ void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *cur #ifdef GLES_OVER_GL if (polygon->antialiased) { glEnable(GL_LINE_SMOOTH); - if (polygon->antialiasing_use_indices) { - _draw_generic_indices(GL_LINE_STRIP, polygon->indices.ptr(), polygon->count, polygon->points.size(), polygon->points.ptr(), polygon->uvs.ptr(), polygon->colors.ptr(), polygon->colors.size() == 1); - } else { - _draw_generic(GL_LINE_LOOP, polygon->points.size(), polygon->points.ptr(), polygon->uvs.ptr(), polygon->colors.ptr(), polygon->colors.size() == 1); - } + // FIXME: Removed during Vulkan rebase. + //if (polygon->antialiasing_use_indices) { + // _draw_generic_indices(GL_LINE_STRIP, polygon->indices.ptr(), polygon->count, polygon->points.size(), polygon->points.ptr(), polygon->uvs.ptr(), polygon->colors.ptr(), polygon->colors.size() == 1); + //} else + _draw_generic(GL_LINE_LOOP, polygon->points.size(), polygon->points.ptr(), polygon->uvs.ptr(), polygon->colors.ptr(), polygon->colors.size() == 1); glDisable(GL_LINE_SMOOTH); } #endif @@ -1480,7 +1480,7 @@ void RasterizerCanvasGLES2::canvas_render_items(Item *p_item_list, int p_z, cons { //skeleton handling if (ci->skeleton.is_valid() && storage->skeleton_owner.owns(ci->skeleton)) { - skeleton = storage->skeleton_owner.get(ci->skeleton); + skeleton = storage->skeleton_owner.getornull(ci->skeleton); if (!skeleton->use_2d) { skeleton = NULL; } else { @@ -1825,7 +1825,7 @@ void RasterizerCanvasGLES2::canvas_debug_viewport_shadows(Light *p_lights_with_s void RasterizerCanvasGLES2::canvas_light_shadow_buffer_update(RID p_buffer, const Transform2D &p_light_xform, int p_light_mask, float p_near, float p_far, LightOccluderInstance *p_occluders, CameraMatrix *p_xform_cache) { - RasterizerStorageGLES2::CanvasLightShadow *cls = storage->canvas_light_shadow_owner.get(p_buffer); + RasterizerStorageGLES2::CanvasLightShadow *cls = storage->canvas_light_shadow_owner.getornull(p_buffer); ERR_FAIL_COND(!cls); glDisable(GL_BLEND); diff --git a/drivers/gles2/rasterizer_gles2.cpp b/drivers/gles2/rasterizer_gles2.cpp index c4e9541a36..02b956fd44 100644 --- a/drivers/gles2/rasterizer_gles2.cpp +++ b/drivers/gles2/rasterizer_gles2.cpp @@ -130,7 +130,7 @@ static void GLAPIENTRY _gl_debug_print(GLenum source, GLenum type, GLuint id, GL String output = String() + "GL ERROR: Source: " + debSource + "\tType: " + debType + "\tID: " + itos(id) + "\tSeverity: " + debSev + "\tMessage: " + message; - ERR_PRINTS(output); + ERR_PRINT(output); } #endif // CAN_DEBUG @@ -384,7 +384,7 @@ void RasterizerGLES2::set_boot_image(const Ref<Image> &p_image, const Color &p_c screenrect.position += ((Size2(window_w, window_h) - screenrect.size) / 2.0).floor(); } - RasterizerStorageGLES2::Texture *t = storage->texture_owner.get(texture); + RasterizerStorageGLES2::Texture *t = storage->texture_owner.getornull(texture); glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 1); glBindTexture(GL_TEXTURE_2D, t->tex_id); canvas->draw_generic_textured_rect(screenrect, Rect2(0, 0, 1, 1)); diff --git a/drivers/gles2/rasterizer_scene_gles2.cpp b/drivers/gles2/rasterizer_scene_gles2.cpp index c0ba93db6a..2e35bd0ccf 100644 --- a/drivers/gles2/rasterizer_scene_gles2.cpp +++ b/drivers/gles2/rasterizer_scene_gles2.cpp @@ -53,6 +53,11 @@ #endif #endif +#if !defined(GLES_OVER_GL) +#define GL_TEXTURE_2D_ARRAY 0x8C1A +#define GL_TEXTURE_3D 0x806F +#endif + static const GLenum _cube_side_enum[6] = { GL_TEXTURE_CUBE_MAP_NEGATIVE_X, @@ -365,7 +370,7 @@ bool RasterizerSceneGLES2::shadow_atlas_update_light(RID p_atlas, RID p_light_in // it is take but invalid, so we can take it shadow_atlas->shadow_owners.erase(sh->owner); - LightInstance *sli = light_instance_owner.get(sh->owner); + LightInstance *sli = light_instance_owner.getornull(sh->owner); sli->shadow_atlases.erase(p_atlas); } @@ -407,7 +412,7 @@ bool RasterizerSceneGLES2::shadow_atlas_update_light(RID p_atlas, RID p_light_in // it is take but invalid, so we can take it shadow_atlas->shadow_owners.erase(sh->owner); - LightInstance *sli = light_instance_owner.get(sh->owner); + LightInstance *sli = light_instance_owner.getornull(sh->owner); sli->shadow_atlases.erase(p_atlas); } @@ -971,7 +976,7 @@ void RasterizerSceneGLES2::_add_geometry(RasterizerStorageGLES2::Geometry *p_geo } if (!material) { - material = storage->material_owner.getptr(default_material); + material = storage->material_owner.getornull(default_material); } ERR_FAIL_COND(!material); @@ -1018,10 +1023,10 @@ void RasterizerSceneGLES2::_add_geometry_with_material(RasterizerStorageGLES2::G if (!p_material->shader->spatial.uses_alpha_scissor && !p_material->shader->spatial.writes_modelview_or_projection && !p_material->shader->spatial.uses_vertex && !p_material->shader->spatial.uses_discard && p_material->shader->spatial.depth_draw_mode != RasterizerStorageGLES2::Shader::Spatial::DEPTH_DRAW_ALPHA_PREPASS) { //shader does not use discard and does not write a vertex position, use generic material if (p_instance->cast_shadows == VS::SHADOW_CASTING_SETTING_DOUBLE_SIDED) { - p_material = storage->material_owner.getptr(!p_shadow_pass && p_material->shader->spatial.uses_world_coordinates ? default_worldcoord_material_twosided : default_material_twosided); + p_material = storage->material_owner.getornull(!p_shadow_pass && p_material->shader->spatial.uses_world_coordinates ? default_worldcoord_material_twosided : default_material_twosided); mirror = false; } else { - p_material = storage->material_owner.getptr(!p_shadow_pass && p_material->shader->spatial.uses_world_coordinates ? default_worldcoord_material : default_material); + p_material = storage->material_owner.getornull(!p_shadow_pass && p_material->shader->spatial.uses_world_coordinates ? default_worldcoord_material : default_material); } } @@ -1237,13 +1242,13 @@ void RasterizerSceneGLES2::_fill_render_list(InstanceBase **p_cull_result, int p } break; case VS::INSTANCE_MULTIMESH: { - RasterizerStorageGLES2::MultiMesh *multi_mesh = storage->multimesh_owner.getptr(instance->base); + RasterizerStorageGLES2::MultiMesh *multi_mesh = storage->multimesh_owner.getornull(instance->base); ERR_CONTINUE(!multi_mesh); if (multi_mesh->size == 0 || multi_mesh->visible_instances == 0) continue; - RasterizerStorageGLES2::Mesh *mesh = storage->mesh_owner.getptr(multi_mesh->mesh); + RasterizerStorageGLES2::Mesh *mesh = storage->mesh_owner.getornull(multi_mesh->mesh); if (!mesh) continue; @@ -1256,7 +1261,7 @@ void RasterizerSceneGLES2::_fill_render_list(InstanceBase **p_cull_result, int p } break; case VS::INSTANCE_IMMEDIATE: { - RasterizerStorageGLES2::Immediate *im = storage->immediate_owner.getptr(instance->base); + RasterizerStorageGLES2::Immediate *im = storage->immediate_owner.getornull(instance->base); ERR_CONTINUE(!im); _add_geometry(im, instance, NULL, -1, p_depth_pass, p_shadow_pass); @@ -1343,6 +1348,7 @@ bool RasterizerSceneGLES2::_setup_material(RasterizerStorageGLES2::Material *p_m const Pair<StringName, RID> *textures = p_material->textures.ptr(); const ShaderLanguage::ShaderNode::Uniform::Hint *texture_hints = p_material->shader->texture_hints.ptr(); + const ShaderLanguage::DataType *texture_types = p_material->shader->texture_types.ptr(); state.scene_shader.set_uniform(SceneShaderGLES2::SKELETON_TEXTURE_SIZE, p_skeleton_tex_size); @@ -1356,22 +1362,66 @@ bool RasterizerSceneGLES2::_setup_material(RasterizerStorageGLES2::Material *p_m if (!t) { - switch (texture_hints[i]) { - case ShaderLanguage::ShaderNode::Uniform::HINT_BLACK_ALBEDO: - case ShaderLanguage::ShaderNode::Uniform::HINT_BLACK: { - glBindTexture(GL_TEXTURE_2D, storage->resources.black_tex); + GLenum target = GL_TEXTURE_2D; + GLuint tex = 0; + switch (texture_types[i]) { + case ShaderLanguage::TYPE_ISAMPLER2D: + case ShaderLanguage::TYPE_USAMPLER2D: + case ShaderLanguage::TYPE_SAMPLER2D: { + + switch (texture_hints[i]) { + case ShaderLanguage::ShaderNode::Uniform::HINT_BLACK_ALBEDO: + case ShaderLanguage::ShaderNode::Uniform::HINT_BLACK: { + tex = storage->resources.black_tex; + } break; + case ShaderLanguage::ShaderNode::Uniform::HINT_ANISO: { + tex = storage->resources.aniso_tex; + } break; + case ShaderLanguage::ShaderNode::Uniform::HINT_NORMAL: { + tex = storage->resources.normal_tex; + } break; + default: { + tex = storage->resources.white_tex; + } break; + } + + } break; + + case ShaderLanguage::TYPE_SAMPLERCUBE: { + // TODO } break; - case ShaderLanguage::ShaderNode::Uniform::HINT_ANISO: { - glBindTexture(GL_TEXTURE_2D, storage->resources.aniso_tex); + + case ShaderLanguage::TYPE_ISAMPLER3D: + case ShaderLanguage::TYPE_USAMPLER3D: + case ShaderLanguage::TYPE_SAMPLER3D: { + + target = GL_TEXTURE_3D; + tex = storage->resources.white_tex_3d; + + //switch (texture_hints[i]) { + // TODO + //} + } break; - case ShaderLanguage::ShaderNode::Uniform::HINT_NORMAL: { - glBindTexture(GL_TEXTURE_2D, storage->resources.normal_tex); + + case ShaderLanguage::TYPE_ISAMPLER2DARRAY: + case ShaderLanguage::TYPE_USAMPLER2DARRAY: + case ShaderLanguage::TYPE_SAMPLER2DARRAY: { + + target = GL_TEXTURE_2D_ARRAY; + tex = storage->resources.white_tex_array; + + //switch (texture_hints[i]) { + // TODO + //} + } break; + default: { - glBindTexture(GL_TEXTURE_2D, storage->resources.white_tex); - } break; + } } + glBindTexture(target, tex); continue; } @@ -1739,7 +1789,7 @@ void RasterizerSceneGLES2::_render_geometry(RenderList::Element *p_element) { storage->info.render.vertices_count += vertices; if (c.texture.is_valid() && storage->texture_owner.owns(c.texture)) { - RasterizerStorageGLES2::Texture *t = storage->texture_owner.get(c.texture); + RasterizerStorageGLES2::Texture *t = storage->texture_owner.getornull(c.texture); if (t->redraw_if_visible) { VisualServerRaster::redraw_request(); @@ -3106,9 +3156,9 @@ void RasterizerSceneGLES2::_post_process(Environment *env, const CameraMatrix &p } } - state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_SCREEN, env->glow_blend_mode == VS::GLOW_BLEND_MODE_SCREEN); - state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_SOFTLIGHT, env->glow_blend_mode == VS::GLOW_BLEND_MODE_SOFTLIGHT); - state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_REPLACE, env->glow_blend_mode == VS::GLOW_BLEND_MODE_REPLACE); + state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_SCREEN, env->glow_blend_mode == VS::ENV_GLOW_BLEND_MODE_SCREEN); + state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_SOFTLIGHT, env->glow_blend_mode == VS::ENV_GLOW_BLEND_MODE_SOFTLIGHT); + state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_REPLACE, env->glow_blend_mode == VS::ENV_GLOW_BLEND_MODE_REPLACE); } //Adjustments @@ -3824,11 +3874,11 @@ bool RasterizerSceneGLES2::free(RID p_rid) { if (light_instance_owner.owns(p_rid)) { - LightInstance *light_instance = light_instance_owner.getptr(p_rid); + LightInstance *light_instance = light_instance_owner.getornull(p_rid); //remove from shadow atlases.. for (Set<RID>::Element *E = light_instance->shadow_atlases.front(); E; E = E->next()) { - ShadowAtlas *shadow_atlas = shadow_atlas_owner.get(E->get()); + ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(E->get()); ERR_CONTINUE(!shadow_atlas->shadow_owners.has(p_rid)); uint32_t key = shadow_atlas->shadow_owners[p_rid]; uint32_t q = (key >> ShadowAtlas::QUADRANT_SHIFT) & 0x3; @@ -3843,13 +3893,13 @@ bool RasterizerSceneGLES2::free(RID p_rid) { } else if (shadow_atlas_owner.owns(p_rid)) { - ShadowAtlas *shadow_atlas = shadow_atlas_owner.get(p_rid); + ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_rid); shadow_atlas_set_size(p_rid, 0); shadow_atlas_owner.free(p_rid); memdelete(shadow_atlas); } else if (reflection_probe_instance_owner.owns(p_rid)) { - ReflectionProbeInstance *reflection_instance = reflection_probe_instance_owner.get(p_rid); + ReflectionProbeInstance *reflection_instance = reflection_probe_instance_owner.getornull(p_rid); for (int i = 0; i < 6; i++) { glDeleteFramebuffers(1, &reflection_instance->fbo[i]); diff --git a/drivers/gles2/rasterizer_scene_gles2.h b/drivers/gles2/rasterizer_scene_gles2.h index 74adae05aa..174cdd8e2e 100644 --- a/drivers/gles2/rasterizer_scene_gles2.h +++ b/drivers/gles2/rasterizer_scene_gles2.h @@ -38,19 +38,6 @@ #include "shaders/effect_blur.glsl.gen.h" #include "shaders/scene.glsl.gen.h" #include "shaders/tonemap.glsl.gen.h" -/* - - -#include "drivers/gles3/shaders/exposure.glsl.gen.h" -#include "drivers/gles3/shaders/resolve.glsl.gen.h" -#include "drivers/gles3/shaders/scene.glsl.gen.h" -#include "drivers/gles3/shaders/screen_space_reflection.glsl.gen.h" -#include "drivers/gles3/shaders/ssao.glsl.gen.h" -#include "drivers/gles3/shaders/ssao_blur.glsl.gen.h" -#include "drivers/gles3/shaders/ssao_minify.glsl.gen.h" -#include "drivers/gles3/shaders/subsurf_scattering.glsl.gen.h" - -*/ class RasterizerSceneGLES2 : public RasterizerScene { public: @@ -109,103 +96,6 @@ public: Color default_ambient; Color default_bg; - // ResolveShaderGLES3 resolve_shader; - // ScreenSpaceReflectionShaderGLES3 ssr_shader; - // EffectBlurShaderGLES3 effect_blur_shader; - // SubsurfScatteringShaderGLES3 sss_shader; - // SsaoMinifyShaderGLES3 ssao_minify_shader; - // SsaoShaderGLES3 ssao_shader; - // SsaoBlurShaderGLES3 ssao_blur_shader; - // ExposureShaderGLES3 exposure_shader; - - /* - struct SceneDataUBO { - //this is a std140 compatible struct. Please read the OpenGL 3.3 Specificaiton spec before doing any changes - float projection_matrix[16]; - float inv_projection_matrix[16]; - float camera_inverse_matrix[16]; - float camera_matrix[16]; - float ambient_light_color[4]; - float bg_color[4]; - float fog_color_enabled[4]; - float fog_sun_color_amount[4]; - - float ambient_energy; - float bg_energy; - float z_offset; - float z_slope_scale; - float shadow_dual_paraboloid_render_zfar; - float shadow_dual_paraboloid_render_side; - float viewport_size[2]; - float screen_pixel_size[2]; - float shadow_atlas_pixel_size[2]; - float shadow_directional_pixel_size[2]; - - float time; - float z_far; - float reflection_multiplier; - float subsurface_scatter_width; - float ambient_occlusion_affect_light; - - uint32_t fog_depth_enabled; - float fog_depth_begin; - float fog_depth_curve; - uint32_t fog_transmit_enabled; - float fog_transmit_curve; - uint32_t fog_height_enabled; - float fog_height_min; - float fog_height_max; - float fog_height_curve; - // make sure this struct is padded to be a multiple of 16 bytes for webgl - - } ubo_data; - - GLuint scene_ubo; - - struct EnvironmentRadianceUBO { - - float transform[16]; - float ambient_contribution; - uint8_t padding[12]; - - } env_radiance_data; - - GLuint env_radiance_ubo; - - GLuint sky_array; - - GLuint directional_ubo; - - GLuint spot_array_ubo; - GLuint omni_array_ubo; - GLuint reflection_array_ubo; - - GLuint immediate_buffer; - GLuint immediate_array; - - uint32_t ubo_light_size; - uint8_t *spot_array_tmp; - uint8_t *omni_array_tmp; - uint8_t *reflection_array_tmp; - - int max_ubo_lights; - int max_forward_lights_per_object; - int max_ubo_reflections; - int max_skeleton_bones; - - bool used_contact_shadows; - - int spot_light_count; - int omni_light_count; - int directional_light_count; - int reflection_probe_count; - - bool used_sss; - bool using_contact_shadows; - - VS::ViewportDebugDraw debug_draw; - */ - bool cull_front; bool cull_disabled; @@ -225,7 +115,7 @@ public: uint64_t shadow_atlas_realloc_tolerance_msec; - struct ShadowAtlas : public RID_Data { + struct ShadowAtlas { enum { QUADRANT_SHIFT = 27, SHADOW_INDEX_MASK = (1 << QUADRANT_SHIFT) - 1, @@ -273,7 +163,7 @@ public: Vector<ShadowCubeMap> shadow_cubemaps; - RID_Owner<ShadowAtlas> shadow_atlas_owner; + RID_PtrOwner<ShadowAtlas> shadow_atlas_owner; RID shadow_atlas_create(); void shadow_atlas_set_size(RID p_atlas, int p_size); @@ -304,7 +194,7 @@ public: /* REFLECTION PROBE INSTANCE */ - struct ReflectionProbeInstance : public RID_Data { + struct ReflectionProbeInstance { RasterizerStorageGLES2::ReflectionProbe *probe_ptr; RID probe; @@ -330,7 +220,7 @@ public: Transform transform; }; - mutable RID_Owner<ReflectionProbeInstance> reflection_probe_instance_owner; + mutable RID_PtrOwner<ReflectionProbeInstance> reflection_probe_instance_owner; ReflectionProbeInstance **reflection_probe_instances; int reflection_probe_count; @@ -345,7 +235,7 @@ public: /* ENVIRONMENT API */ - struct Environment : public RID_Data { + struct Environment { VS::EnvironmentBG bg_mode; RID sky; @@ -423,7 +313,7 @@ public: glow_intensity(0.8), glow_strength(1.0), glow_bloom(0.0), - glow_blend_mode(VS::GLOW_BLEND_MODE_SOFTLIGHT), + glow_blend_mode(VS::ENV_GLOW_BLEND_MODE_SOFTLIGHT), glow_hdr_bleed_threshold(1.0), glow_hdr_bleed_scale(2.0), glow_hdr_luminance_cap(12.0), @@ -459,7 +349,7 @@ public: } }; - mutable RID_Owner<Environment> environment_owner; + mutable RID_PtrOwner<Environment> environment_owner; virtual RID environment_create(); @@ -496,7 +386,7 @@ public: /* LIGHT INSTANCE */ - struct LightInstance : public RID_Data { + struct LightInstance { struct ShadowTransform { CameraMatrix camera; @@ -530,7 +420,7 @@ public: Set<RID> shadow_atlases; // atlases where this light is registered }; - mutable RID_Owner<LightInstance> light_instance_owner; + mutable RID_PtrOwner<LightInstance> light_instance_owner; virtual RID light_instance_create(RID p_light); virtual void light_instance_set_transform(RID p_light_instance, const Transform &p_transform); diff --git a/drivers/gles2/rasterizer_storage_gles2.cpp b/drivers/gles2/rasterizer_storage_gles2.cpp index cd6a7d86c6..245531a935 100644 --- a/drivers/gles2/rasterizer_storage_gles2.cpp +++ b/drivers/gles2/rasterizer_storage_gles2.cpp @@ -103,6 +103,13 @@ PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC glFramebufferTexture2DMultisampleEXT #define glRenderbufferStorageMultisample glRenderbufferStorageMultisampleEXT #define glFramebufferTexture2DMultisample glFramebufferTexture2DMultisampleEXT +PFNGLTEXIMAGE3DOESPROC glTexImage3DOES; +PFNGLTEXSUBIMAGE3DOESPROC glTexSubImage3DOES; +PFNGLCOMPRESSEDTEXSUBIMAGE3DOESPROC glCompressedTexSubImage3DOES; +#define glTexImage3D glTexImage3DOES +#define glTexSubImage3D glTexSubImage3DOES +#define glCompressedTexSubImage3D glCompressedTexSubImage3DOES + #elif defined(UWP_ENABLED) #include <GLES2/gl2ext.h> #define glRenderbufferStorageMultisample glRenderbufferStorageMultisampleANGLE @@ -113,6 +120,11 @@ PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC glFramebufferTexture2DMultisampleEXT #define GL_MAX_SAMPLES 0x8D57 #endif //!GLES_OVER_GL +#if !defined(GLES_OVER_GL) +#define GL_TEXTURE_2D_ARRAY 0x8C1A +#define GL_TEXTURE_3D 0x806F +#endif + void RasterizerStorageGLES2::bind_quad_array() const { glBindBuffer(GL_ARRAY_BUFFER, resources.quadie); glVertexAttribPointer(VS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 4, 0); @@ -182,7 +194,7 @@ Ref<Image> RasterizerStorageGLES2::_get_gl_image_and_format(const Ref<Image> &p_ r_gl_type = GL_UNSIGNED_SHORT_4_4_4_4; } break; - case Image::FORMAT_RGBA5551: { + case Image::FORMAT_RGB565: { r_gl_internal_format = GL_RGB5_A1; r_gl_format = GL_RGBA; @@ -566,11 +578,23 @@ void RasterizerStorageGLES2::texture_allocate(RID p_texture, int p_width, int p_ texture->target = GL_TEXTURE_CUBE_MAP; texture->images.resize(6); } break; - case VS::TEXTURE_TYPE_2D_ARRAY: + case VS::TEXTURE_TYPE_2D_ARRAY: { + if (config.texture_array_supported) { + texture->target = GL_TEXTURE_2D_ARRAY; + texture->images.resize(p_depth_3d); + } else { + WARN_PRINT_ONCE("Texture Arrays not supported on this hardware."); + return; + } + } break; case VS::TEXTURE_TYPE_3D: { - texture->target = GL_TEXTURE_3D; - ERR_PRINT("3D textures and Texture Arrays are not supported in GLES2. Please switch to the GLES3 backend."); - return; + if (config.texture_3d_supported) { + texture->target = GL_TEXTURE_3D; + texture->images.resize(p_depth_3d); + } else { + WARN_PRINT_ONCE("3D textures not supported on this hardware."); + return; + } } break; default: { ERR_PRINT("Unknown texture type!"); @@ -591,7 +615,7 @@ void RasterizerStorageGLES2::texture_allocate(RID p_texture, int p_width, int p_ if (p_flags & VS::TEXTURE_FLAG_USED_FOR_STREAMING) { //not supported - ERR_PRINTS("Streaming texture for non power of 2 or has mipmaps on this hardware: " + texture->path + "'. Mipmaps and repeat disabled."); + ERR_PRINT("Streaming texture for non power of 2 or has mipmaps on this hardware: " + texture->path + "'. Mipmaps and repeat disabled."); texture->flags &= ~(VS::TEXTURE_FLAG_REPEAT | VS::TEXTURE_FLAG_MIPMAPS); } else { texture->alloc_height = po2_height; @@ -615,7 +639,42 @@ void RasterizerStorageGLES2::texture_allocate(RID p_texture, int p_width, int p_ glActiveTexture(GL_TEXTURE0); glBindTexture(texture->target, texture->tex_id); - if (p_flags & VS::TEXTURE_FLAG_USED_FOR_STREAMING) { +#if defined(GLES_OVER_GL) || defined(ANDROID_ENABLED) + if ((p_type == VS::TEXTURE_TYPE_3D && config.texture_3d_supported) || (p_type == VS::TEXTURE_TYPE_2D_ARRAY && config.texture_array_supported)) { + + int width = p_width; + int height = p_height; + int depth = p_depth_3d; + + int mipmaps = 0; + + while (width > 0 || height > 0 || (p_type == VS::TEXTURE_TYPE_3D && depth > 0)) { + width = MAX(1, width); + height = MAX(1, height); + depth = MAX(1, depth); + + glTexImage3D(texture->target, mipmaps, internal_format, width, height, depth, 0, format, type, NULL); + + width /= 2; + height /= 2; + + if (p_type == VS::TEXTURE_TYPE_3D) { + depth /= 2; + } + + mipmaps++; + + if (!(p_flags & VS::TEXTURE_FLAG_MIPMAPS)) + break; + } +#ifdef GLES_OVER_GL + glTexParameteri(texture->target, GL_TEXTURE_BASE_LEVEL, 0); + glTexParameteri(texture->target, GL_TEXTURE_MAX_LEVEL, mipmaps - 1); +#endif + + } else +#endif + if (p_flags & VS::TEXTURE_FLAG_USED_FOR_STREAMING) { //prealloc if video glTexImage2D(texture->target, 0, internal_format, texture->alloc_width, texture->alloc_height, 0, format, type, NULL); } @@ -627,8 +686,7 @@ void RasterizerStorageGLES2::texture_set_data(RID p_texture, const Ref<Image> &p Texture *texture = texture_owner.getornull(p_texture); ERR_FAIL_COND(!texture); - if (texture->target == GL_TEXTURE_3D) { - // Target is set to a 3D texture or array texture, exit early to avoid spamming errors + if ((texture->type == VS::TEXTURE_TYPE_2D_ARRAY && !config.texture_array_supported) || (texture->type == VS::TEXTURE_TYPE_3D && !config.texture_3d_supported)) { return; } ERR_FAIL_COND(!texture->active); @@ -650,7 +708,7 @@ void RasterizerStorageGLES2::texture_set_data(RID p_texture, const Ref<Image> &p if (texture->resize_to_po2) { if (p_image->is_compressed()) { - ERR_PRINTS("Texture '" + texture->path + "' is required to be a power of 2 because it uses either mipmaps or repeat, so it was decompressed. This will hurt performance and memory usage."); + ERR_PRINT("Texture '" + texture->path + "' is required to be a power of 2 because it uses either mipmaps or repeat, so it was decompressed. This will hurt performance and memory usage."); } if (img == p_image) { @@ -673,7 +731,23 @@ void RasterizerStorageGLES2::texture_set_data(RID p_texture, const Ref<Image> &p } } - GLenum blit_target = (texture->target == GL_TEXTURE_CUBE_MAP) ? _cube_side_enum[p_layer] : GL_TEXTURE_2D; + GLenum blit_target = GL_TEXTURE_2D; + + switch (texture->type) { + case VS::TEXTURE_TYPE_2D: { + blit_target = GL_TEXTURE_2D; + } break; + case VS::TEXTURE_TYPE_CUBEMAP: { + ERR_FAIL_INDEX(p_layer, 6); + blit_target = _cube_side_enum[p_layer]; + } break; + case VS::TEXTURE_TYPE_2D_ARRAY: { + blit_target = GL_TEXTURE_2D_ARRAY; + } break; + case VS::TEXTURE_TYPE_3D: { + blit_target = GL_TEXTURE_3D; + } break; + } texture->data_size = img->get_data().size(); PoolVector<uint8_t>::Read read = img->get_data().read(); @@ -730,23 +804,41 @@ void RasterizerStorageGLES2::texture_set_data(RID p_texture, const Ref<Image> &p int size, ofs; img->get_mipmap_offset_and_size(i, ofs, size); + if (texture->type == VS::TEXTURE_TYPE_2D || texture->type == VS::TEXTURE_TYPE_CUBEMAP) { - if (compressed) { - glPixelStorei(GL_UNPACK_ALIGNMENT, 4); + if (compressed) { + glPixelStorei(GL_UNPACK_ALIGNMENT, 4); - int bw = w; - int bh = h; + int bw = w; + int bh = h; - glCompressedTexImage2D(blit_target, i, internal_format, bw, bh, 0, size, &read[ofs]); - } else { + glCompressedTexImage2D(blit_target, i, internal_format, bw, bh, 0, size, &read[ofs]); + } else { - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - if (texture->flags & VS::TEXTURE_FLAG_USED_FOR_STREAMING) { - glTexSubImage2D(blit_target, i, 0, 0, w, h, format, type, &read[ofs]); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + if (texture->flags & VS::TEXTURE_FLAG_USED_FOR_STREAMING) { + glTexSubImage2D(blit_target, i, 0, 0, w, h, format, type, &read[ofs]); + } else { + glTexImage2D(blit_target, i, internal_format, w, h, 0, format, type, &read[ofs]); + } + } + } +#if defined(GLES_OVER_GL) || defined(ANDROID_ENABLED) + else { + if (texture->compressed) { + glPixelStorei(GL_UNPACK_ALIGNMENT, 4); + + int bw = w; + int bh = h; + + glCompressedTexSubImage3D(blit_target, i, 0, 0, p_layer, bw, bh, 1, internal_format, size, &read[ofs]); } else { - glTexImage2D(blit_target, i, internal_format, w, h, 0, format, type, &read[ofs]); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + + glTexSubImage3D(blit_target, i, 0, 0, p_layer, w, h, 1, format, type, &read[ofs]); } } +#endif tsize += size; @@ -1092,7 +1184,7 @@ void RasterizerStorageGLES2::texture_set_proxy(RID p_texture, RID p_proxy) { } if (p_proxy.is_valid()) { - Texture *proxy = texture_owner.get(p_proxy); + Texture *proxy = texture_owner.getornull(p_proxy); ERR_FAIL_COND(!proxy); ERR_FAIL_COND(proxy == texture); proxy->proxy_owners.insert(texture); @@ -1109,7 +1201,7 @@ void RasterizerStorageGLES2::texture_set_force_redraw_if_visible(RID p_texture, } void RasterizerStorageGLES2::texture_set_detect_3d_callback(RID p_texture, VisualServer::TextureDetectCallback p_callback, void *p_userdata) { - Texture *texture = texture_owner.get(p_texture); + Texture *texture = texture_owner.getornull(p_texture); ERR_FAIL_COND(!texture); texture->detect_3d = p_callback; @@ -1117,7 +1209,7 @@ void RasterizerStorageGLES2::texture_set_detect_3d_callback(RID p_texture, Visua } void RasterizerStorageGLES2::texture_set_detect_srgb_callback(RID p_texture, VisualServer::TextureDetectCallback p_callback, void *p_userdata) { - Texture *texture = texture_owner.get(p_texture); + Texture *texture = texture_owner.getornull(p_texture); ERR_FAIL_COND(!texture); texture->detect_srgb = p_callback; @@ -1125,7 +1217,7 @@ void RasterizerStorageGLES2::texture_set_detect_srgb_callback(RID p_texture, Vis } void RasterizerStorageGLES2::texture_set_detect_normal_callback(RID p_texture, VisualServer::TextureDetectCallback p_callback, void *p_userdata) { - Texture *texture = texture_owner.get(p_texture); + Texture *texture = texture_owner.getornull(p_texture); ERR_FAIL_COND(!texture); texture->detect_normal = p_callback; @@ -1364,7 +1456,7 @@ void RasterizerStorageGLES2::shader_set_code(RID p_shader, const String &p_code) String RasterizerStorageGLES2::shader_get_code(RID p_shader) const { - const Shader *shader = shader_owner.get(p_shader); + const Shader *shader = shader_owner.getornull(p_shader); ERR_FAIL_COND_V(!shader, ""); return shader->code; @@ -1492,6 +1584,7 @@ void RasterizerStorageGLES2::_update_shader(Shader *p_shader) const { p_shader->texture_count = gen_code.texture_uniforms.size(); p_shader->texture_hints = gen_code.texture_hints; + p_shader->texture_types = gen_code.texture_types; p_shader->uses_vertex_time = gen_code.uses_vertex_time; p_shader->uses_fragment_time = gen_code.uses_fragment_time; @@ -1517,7 +1610,7 @@ void RasterizerStorageGLES2::update_dirty_shaders() { void RasterizerStorageGLES2::shader_get_param_list(RID p_shader, List<PropertyInfo> *p_param_list) const { - Shader *shader = shader_owner.get(p_shader); + Shader *shader = shader_owner.getornull(p_shader); ERR_FAIL_COND(!shader); if (shader->dirty_list.in_list()) { @@ -1543,6 +1636,9 @@ void RasterizerStorageGLES2::shader_get_param_list(RID p_shader, List<PropertyIn pi.name = E->get(); switch (u.type) { + case ShaderLanguage::TYPE_STRUCT: { + pi.type = Variant::ARRAY; + } break; case ShaderLanguage::TYPE_VOID: { pi.type = Variant::NIL; } break; @@ -1628,7 +1724,7 @@ void RasterizerStorageGLES2::shader_get_param_list(RID p_shader, List<PropertyIn case ShaderLanguage::TYPE_USAMPLER2D: { pi.type = Variant::OBJECT; pi.hint = PROPERTY_HINT_RESOURCE_TYPE; - pi.hint_string = "Texture"; + pi.hint_string = "Texture2D"; } break; case ShaderLanguage::TYPE_SAMPLERCUBE: { @@ -1639,11 +1735,19 @@ void RasterizerStorageGLES2::shader_get_param_list(RID p_shader, List<PropertyIn case ShaderLanguage::TYPE_SAMPLER2DARRAY: case ShaderLanguage::TYPE_ISAMPLER2DARRAY: - case ShaderLanguage::TYPE_USAMPLER2DARRAY: + case ShaderLanguage::TYPE_USAMPLER2DARRAY: { + + pi.type = Variant::OBJECT; + pi.hint = PROPERTY_HINT_RESOURCE_TYPE; + pi.hint_string = "TextureArray"; + } break; + case ShaderLanguage::TYPE_SAMPLER3D: case ShaderLanguage::TYPE_ISAMPLER3D: case ShaderLanguage::TYPE_USAMPLER3D: { - // Not implemented in GLES2 + pi.type = Variant::OBJECT; + pi.hint = PROPERTY_HINT_RESOURCE_TYPE; + pi.hint_string = "Texture3D"; } break; } @@ -1653,7 +1757,7 @@ void RasterizerStorageGLES2::shader_get_param_list(RID p_shader, List<PropertyIn void RasterizerStorageGLES2::shader_set_default_texture_param(RID p_shader, const StringName &p_name, RID p_texture) { - Shader *shader = shader_owner.get(p_shader); + Shader *shader = shader_owner.getornull(p_shader); ERR_FAIL_COND(!shader); ERR_FAIL_COND(p_texture.is_valid() && !texture_owner.owns(p_texture)); @@ -1668,7 +1772,7 @@ void RasterizerStorageGLES2::shader_set_default_texture_param(RID p_shader, cons RID RasterizerStorageGLES2::shader_get_default_texture_param(RID p_shader, const StringName &p_name) const { - const Shader *shader = shader_owner.get(p_shader); + const Shader *shader = shader_owner.getornull(p_shader); ERR_FAIL_COND_V(!shader, RID()); const Map<StringName, RID>::Element *E = shader->default_textures.find(p_name); @@ -1699,7 +1803,7 @@ RID RasterizerStorageGLES2::material_create() { void RasterizerStorageGLES2::material_set_shader(RID p_material, RID p_shader) { - Material *material = material_owner.get(p_material); + Material *material = material_owner.getornull(p_material); ERR_FAIL_COND(!material); Shader *shader = shader_owner.getornull(p_shader); @@ -1720,7 +1824,7 @@ void RasterizerStorageGLES2::material_set_shader(RID p_material, RID p_shader) { RID RasterizerStorageGLES2::material_get_shader(RID p_material) const { - const Material *material = material_owner.get(p_material); + const Material *material = material_owner.getornull(p_material); ERR_FAIL_COND_V(!material, RID()); if (material->shader) { @@ -1732,7 +1836,7 @@ RID RasterizerStorageGLES2::material_get_shader(RID p_material) const { void RasterizerStorageGLES2::material_set_param(RID p_material, const StringName &p_param, const Variant &p_value) { - Material *material = material_owner.get(p_material); + Material *material = material_owner.getornull(p_material); ERR_FAIL_COND(!material); if (p_value.get_type() == Variant::NIL) { @@ -1746,7 +1850,7 @@ void RasterizerStorageGLES2::material_set_param(RID p_material, const StringName Variant RasterizerStorageGLES2::material_get_param(RID p_material, const StringName &p_param) const { - const Material *material = material_owner.get(p_material); + const Material *material = material_owner.getornull(p_material); ERR_FAIL_COND_V(!material, RID()); if (material->params.has(p_param)) { @@ -1757,7 +1861,7 @@ Variant RasterizerStorageGLES2::material_get_param(RID p_material, const StringN } Variant RasterizerStorageGLES2::material_get_param_default(RID p_material, const StringName &p_param) const { - const Material *material = material_owner.get(p_material); + const Material *material = material_owner.getornull(p_material); ERR_FAIL_COND_V(!material, Variant()); if (material->shader) { @@ -1778,14 +1882,14 @@ void RasterizerStorageGLES2::material_set_line_width(RID p_material, float p_wid } void RasterizerStorageGLES2::material_set_next_pass(RID p_material, RID p_next_material) { - Material *material = material_owner.get(p_material); + Material *material = material_owner.getornull(p_material); ERR_FAIL_COND(!material); material->next_pass = p_next_material; } bool RasterizerStorageGLES2::material_is_animated(RID p_material) { - Material *material = material_owner.get(p_material); + Material *material = material_owner.getornull(p_material); ERR_FAIL_COND_V(!material, false); if (material->dirty_list.in_list()) { _update_material(material); @@ -1799,7 +1903,7 @@ bool RasterizerStorageGLES2::material_is_animated(RID p_material) { } bool RasterizerStorageGLES2::material_casts_shadows(RID p_material) { - Material *material = material_owner.get(p_material); + Material *material = material_owner.getornull(p_material); ERR_FAIL_COND_V(!material, false); if (material->dirty_list.in_list()) { _update_material(material); @@ -1846,7 +1950,7 @@ void RasterizerStorageGLES2::material_set_render_priority(RID p_material, int pr ERR_FAIL_COND(priority < VS::MATERIAL_RENDER_PRIORITY_MIN); ERR_FAIL_COND(priority > VS::MATERIAL_RENDER_PRIORITY_MAX); - Material *material = material_owner.get(p_material); + Material *material = material_owner.getornull(p_material); ERR_FAIL_COND(!material); material->render_priority = priority; @@ -2703,7 +2807,7 @@ AABB RasterizerStorageGLES2::mesh_get_custom_aabb(RID p_mesh) const { } AABB RasterizerStorageGLES2::mesh_get_aabb(RID p_mesh, RID p_skeleton) const { - Mesh *mesh = mesh_owner.get(p_mesh); + Mesh *mesh = mesh_owner.getornull(p_mesh); ERR_FAIL_COND_V(!mesh, AABB()); if (mesh->custom_aabb != AABB()) @@ -2711,7 +2815,7 @@ AABB RasterizerStorageGLES2::mesh_get_aabb(RID p_mesh, RID p_skeleton) const { Skeleton *sk = NULL; if (p_skeleton.is_valid()) { - sk = skeleton_owner.get(p_skeleton); + sk = skeleton_owner.getornull(p_skeleton); } AABB aabb; @@ -3367,7 +3471,7 @@ RID RasterizerStorageGLES2::immediate_create() { } void RasterizerStorageGLES2::immediate_begin(RID p_immediate, VS::PrimitiveType p_primitive, RID p_texture) { - Immediate *im = immediate_owner.get(p_immediate); + Immediate *im = immediate_owner.getornull(p_immediate); ERR_FAIL_COND(!im); ERR_FAIL_COND(im->building); @@ -3380,7 +3484,7 @@ void RasterizerStorageGLES2::immediate_begin(RID p_immediate, VS::PrimitiveType } void RasterizerStorageGLES2::immediate_vertex(RID p_immediate, const Vector3 &p_vertex) { - Immediate *im = immediate_owner.get(p_immediate); + Immediate *im = immediate_owner.getornull(p_immediate); ERR_FAIL_COND(!im); ERR_FAIL_COND(!im->building); @@ -3408,7 +3512,7 @@ void RasterizerStorageGLES2::immediate_vertex(RID p_immediate, const Vector3 &p_ } void RasterizerStorageGLES2::immediate_normal(RID p_immediate, const Vector3 &p_normal) { - Immediate *im = immediate_owner.get(p_immediate); + Immediate *im = immediate_owner.getornull(p_immediate); ERR_FAIL_COND(!im); ERR_FAIL_COND(!im->building); @@ -3417,7 +3521,7 @@ void RasterizerStorageGLES2::immediate_normal(RID p_immediate, const Vector3 &p_ } void RasterizerStorageGLES2::immediate_tangent(RID p_immediate, const Plane &p_tangent) { - Immediate *im = immediate_owner.get(p_immediate); + Immediate *im = immediate_owner.getornull(p_immediate); ERR_FAIL_COND(!im); ERR_FAIL_COND(!im->building); @@ -3426,7 +3530,7 @@ void RasterizerStorageGLES2::immediate_tangent(RID p_immediate, const Plane &p_t } void RasterizerStorageGLES2::immediate_color(RID p_immediate, const Color &p_color) { - Immediate *im = immediate_owner.get(p_immediate); + Immediate *im = immediate_owner.getornull(p_immediate); ERR_FAIL_COND(!im); ERR_FAIL_COND(!im->building); @@ -3435,7 +3539,7 @@ void RasterizerStorageGLES2::immediate_color(RID p_immediate, const Color &p_col } void RasterizerStorageGLES2::immediate_uv(RID p_immediate, const Vector2 &tex_uv) { - Immediate *im = immediate_owner.get(p_immediate); + Immediate *im = immediate_owner.getornull(p_immediate); ERR_FAIL_COND(!im); ERR_FAIL_COND(!im->building); @@ -3444,7 +3548,7 @@ void RasterizerStorageGLES2::immediate_uv(RID p_immediate, const Vector2 &tex_uv } void RasterizerStorageGLES2::immediate_uv2(RID p_immediate, const Vector2 &tex_uv) { - Immediate *im = immediate_owner.get(p_immediate); + Immediate *im = immediate_owner.getornull(p_immediate); ERR_FAIL_COND(!im); ERR_FAIL_COND(!im->building); @@ -3453,7 +3557,7 @@ void RasterizerStorageGLES2::immediate_uv2(RID p_immediate, const Vector2 &tex_u } void RasterizerStorageGLES2::immediate_end(RID p_immediate) { - Immediate *im = immediate_owner.get(p_immediate); + Immediate *im = immediate_owner.getornull(p_immediate); ERR_FAIL_COND(!im); ERR_FAIL_COND(!im->building); @@ -3462,7 +3566,7 @@ void RasterizerStorageGLES2::immediate_end(RID p_immediate) { } void RasterizerStorageGLES2::immediate_clear(RID p_immediate) { - Immediate *im = immediate_owner.get(p_immediate); + Immediate *im = immediate_owner.getornull(p_immediate); ERR_FAIL_COND(!im); ERR_FAIL_COND(im->building); @@ -3471,13 +3575,13 @@ void RasterizerStorageGLES2::immediate_clear(RID p_immediate) { } AABB RasterizerStorageGLES2::immediate_get_aabb(RID p_immediate) const { - Immediate *im = immediate_owner.get(p_immediate); + Immediate *im = immediate_owner.getornull(p_immediate); ERR_FAIL_COND_V(!im, AABB()); return im->aabb; } void RasterizerStorageGLES2::immediate_set_material(RID p_immediate, RID p_material) { - Immediate *im = immediate_owner.get(p_immediate); + Immediate *im = immediate_owner.getornull(p_immediate); ERR_FAIL_COND(!im); im->material = p_material; @@ -3485,7 +3589,7 @@ void RasterizerStorageGLES2::immediate_set_material(RID p_immediate, RID p_mater } RID RasterizerStorageGLES2::immediate_get_material(RID p_immediate) const { - const Immediate *im = immediate_owner.get(p_immediate); + const Immediate *im = immediate_owner.getornull(p_immediate); ERR_FAIL_COND_V(!im, RID()); return im->material; } @@ -4709,7 +4813,7 @@ void RasterizerStorageGLES2::_render_target_allocate(RenderTarget *rt) { int max_samples = 0; glGetIntegerv(GL_MAX_SAMPLES, &max_samples); if (msaa > max_samples) { - WARN_PRINTS("MSAA must be <= GL_MAX_SAMPLES, falling-back to GL_MAX_SAMPLES = " + itos(max_samples)); + WARN_PRINT("MSAA must be <= GL_MAX_SAMPLES, falling-back to GL_MAX_SAMPLES = " + itos(max_samples)); msaa = max_samples; } @@ -4956,7 +5060,7 @@ void RasterizerStorageGLES2::_render_target_clear(RenderTarget *rt) { glDeleteFramebuffers(1, &rt->external.fbo); // clean up our texture - Texture *t = texture_owner.get(rt->external.texture); + Texture *t = texture_owner.getornull(rt->external.texture); t->alloc_height = 0; t->alloc_width = 0; t->width = 0; @@ -4978,7 +5082,7 @@ void RasterizerStorageGLES2::_render_target_clear(RenderTarget *rt) { rt->depth = 0; } - Texture *tex = texture_owner.get(rt->texture); + Texture *tex = texture_owner.getornull(rt->texture); tex->alloc_height = 0; tex->alloc_width = 0; tex->width = 0; @@ -5105,7 +5209,7 @@ void RasterizerStorageGLES2::render_target_set_external_texture(RID p_render_tar } // clean up our texture - Texture *t = texture_owner.get(rt->external.texture); + Texture *t = texture_owner.getornull(rt->external.texture); t->alloc_height = 0; t->alloc_width = 0; t->width = 0; @@ -5157,7 +5261,7 @@ void RasterizerStorageGLES2::render_target_set_external_texture(RID p_render_tar glBindFramebuffer(GL_FRAMEBUFFER, rt->external.fbo); // find our texture - t = texture_owner.get(rt->external.texture); + t = texture_owner.getornull(rt->external.texture); } // set our texture @@ -5257,7 +5361,7 @@ bool RasterizerStorageGLES2::render_target_was_used(RID p_render_target) { return rt->used_in_frame; } -void RasterizerStorageGLES2::render_target_clear_used(RID p_render_target) { +void RasterizerStorageGLES2::render_target_set_as_unused(RID p_render_target) { RenderTarget *rt = render_target_owner.getornull(p_render_target); ERR_FAIL_COND(!rt); @@ -5347,7 +5451,7 @@ RID RasterizerStorageGLES2::canvas_light_occluder_create() { void RasterizerStorageGLES2::canvas_light_occluder_set_polylines(RID p_occluder, const PoolVector<Vector2> &p_lines) { - CanvasOccluder *co = canvas_occluder_owner.get(p_occluder); + CanvasOccluder *co = canvas_occluder_owner.getornull(p_occluder); ERR_FAIL_COND(!co); co->lines = p_lines; @@ -5464,7 +5568,7 @@ bool RasterizerStorageGLES2::free(RID p_rid) { RenderTarget *rt = render_target_owner.getornull(p_rid); _render_target_clear(rt); - Texture *t = texture_owner.get(rt->texture); + Texture *t = texture_owner.getornull(rt->texture); texture_owner.free(rt->texture); memdelete(t); render_target_owner.free(p_rid); @@ -5473,7 +5577,7 @@ bool RasterizerStorageGLES2::free(RID p_rid) { return true; } else if (texture_owner.owns(p_rid)) { - Texture *t = texture_owner.get(p_rid); + Texture *t = texture_owner.getornull(p_rid); // can't free a render target texture ERR_FAIL_COND_V(t->render_target, true); @@ -5484,7 +5588,7 @@ bool RasterizerStorageGLES2::free(RID p_rid) { return true; } else if (sky_owner.owns(p_rid)) { - Sky *sky = sky_owner.get(p_rid); + Sky *sky = sky_owner.getornull(p_rid); sky_set_texture(p_rid, RID(), 256); sky_owner.free(p_rid); memdelete(sky); @@ -5492,7 +5596,7 @@ bool RasterizerStorageGLES2::free(RID p_rid) { return true; } else if (shader_owner.owns(p_rid)) { - Shader *shader = shader_owner.get(p_rid); + Shader *shader = shader_owner.getornull(p_rid); if (shader->shader && shader->custom_code_id) { shader->shader->free_custom_shader(shader->custom_code_id); @@ -5517,7 +5621,7 @@ bool RasterizerStorageGLES2::free(RID p_rid) { return true; } else if (material_owner.owns(p_rid)) { - Material *m = material_owner.get(p_rid); + Material *m = material_owner.getornull(p_rid); if (m->shader) { m->shader->materials.remove(&m->list); @@ -5549,7 +5653,7 @@ bool RasterizerStorageGLES2::free(RID p_rid) { return true; } else if (skeleton_owner.owns(p_rid)) { - Skeleton *s = skeleton_owner.get(p_rid); + Skeleton *s = skeleton_owner.getornull(p_rid); if (s->update_list.in_list()) { skeleton_update_list.remove(&s->update_list); @@ -5571,7 +5675,7 @@ bool RasterizerStorageGLES2::free(RID p_rid) { return true; } else if (mesh_owner.owns(p_rid)) { - Mesh *mesh = mesh_owner.get(p_rid); + Mesh *mesh = mesh_owner.getornull(p_rid); mesh->instance_remove_deps(); mesh_clear(p_rid); @@ -5594,7 +5698,7 @@ bool RasterizerStorageGLES2::free(RID p_rid) { return true; } else if (multimesh_owner.owns(p_rid)) { - MultiMesh *multimesh = multimesh_owner.get(p_rid); + MultiMesh *multimesh = multimesh_owner.getornull(p_rid); multimesh->instance_remove_deps(); if (multimesh->mesh.is_valid()) { @@ -5613,7 +5717,7 @@ bool RasterizerStorageGLES2::free(RID p_rid) { return true; } else if (immediate_owner.owns(p_rid)) { - Immediate *im = immediate_owner.get(p_rid); + Immediate *im = immediate_owner.getornull(p_rid); im->instance_remove_deps(); immediate_owner.free(p_rid); @@ -5622,7 +5726,7 @@ bool RasterizerStorageGLES2::free(RID p_rid) { return true; } else if (light_owner.owns(p_rid)) { - Light *light = light_owner.get(p_rid); + Light *light = light_owner.getornull(p_rid); light->instance_remove_deps(); light_owner.free(p_rid); @@ -5632,7 +5736,7 @@ bool RasterizerStorageGLES2::free(RID p_rid) { } else if (reflection_probe_owner.owns(p_rid)) { // delete the texture - ReflectionProbe *reflection_probe = reflection_probe_owner.get(p_rid); + ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_rid); reflection_probe->instance_remove_deps(); reflection_probe_owner.free(p_rid); @@ -5642,7 +5746,7 @@ bool RasterizerStorageGLES2::free(RID p_rid) { } else if (lightmap_capture_data_owner.owns(p_rid)) { // delete the texture - LightmapCapture *lightmap_capture = lightmap_capture_data_owner.get(p_rid); + LightmapCapture *lightmap_capture = lightmap_capture_data_owner.getornull(p_rid); lightmap_capture->instance_remove_deps(); lightmap_capture_data_owner.free(p_rid); @@ -5651,7 +5755,7 @@ bool RasterizerStorageGLES2::free(RID p_rid) { } else if (canvas_occluder_owner.owns(p_rid)) { - CanvasOccluder *co = canvas_occluder_owner.get(p_rid); + CanvasOccluder *co = canvas_occluder_owner.getornull(p_rid); if (co->index_id) glDeleteBuffers(1, &co->index_id); if (co->vertex_id) @@ -5664,7 +5768,7 @@ bool RasterizerStorageGLES2::free(RID p_rid) { } else if (canvas_light_shadow_owner.owns(p_rid)) { - CanvasLightShadow *cls = canvas_light_shadow_owner.get(p_rid); + CanvasLightShadow *cls = canvas_light_shadow_owner.getornull(p_rid); glDeleteFramebuffers(1, &cls->fbo); glDeleteRenderbuffers(1, &cls->depth); glDeleteTextures(1, &cls->distance); @@ -5795,6 +5899,8 @@ void RasterizerStorageGLES2::initialize() { config.depth_type = GL_UNSIGNED_INT; #ifdef GLES_OVER_GL + config.texture_3d_supported = true; + config.texture_array_supported = config.extensions.has("GL_EXT_texture_array"); config.float_texture_supported = true; config.s3tc_supported = true; config.pvrtc_supported = false; @@ -5802,6 +5908,8 @@ void RasterizerStorageGLES2::initialize() { config.support_npot_repeat_mipmap = true; config.depth_buffer_internalformat = GL_DEPTH_COMPONENT24; #else + config.texture_3d_supported = config.extensions.has("GL_OES_texture_3D"); + config.texture_array_supported = false; config.float_texture_supported = config.extensions.has("GL_ARB_texture_float") || config.extensions.has("GL_OES_texture_float"); config.s3tc_supported = config.extensions.has("GL_EXT_texture_compression_s3tc") || config.extensions.has("WEBGL_compressed_texture_s3tc"); config.etc1_supported = config.extensions.has("GL_OES_compressed_ETC1_RGB8_texture") || config.extensions.has("WEBGL_compressed_texture_etc1"); @@ -5840,6 +5948,9 @@ void RasterizerStorageGLES2::initialize() { void *gles2_lib = dlopen("libGLESv2.so", RTLD_LAZY); glRenderbufferStorageMultisampleEXT = (PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC)dlsym(gles2_lib, "glRenderbufferStorageMultisampleEXT"); glFramebufferTexture2DMultisampleEXT = (PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC)dlsym(gles2_lib, "glFramebufferTexture2DMultisampleEXT"); + glTexImage3DOES = (PFNGLTEXIMAGE3DOESPROC)dlsym(gles2_lib, "glTexImage3DOES"); + glTexSubImage3DOES = (PFNGLTEXSUBIMAGE3DOESPROC)dlsym(gles2_lib, "glTexSubImage3DOES"); + glCompressedTexSubImage3DOES = (PFNGLCOMPRESSEDTEXSUBIMAGE3DOESPROC)dlsym(gles2_lib, "glCompressedTexSubImage3DOES"); #endif #endif @@ -6062,6 +6173,26 @@ void RasterizerStorageGLES2::initialize() { glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 8, 8, 0, GL_RGB, GL_UNSIGNED_BYTE, anisotexdata); glGenerateMipmap(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, 0); + +#if defined(GLES_OVER_GL) || defined(ANDROID_ENABLED) + glGenTextures(1, &resources.white_tex_3d); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_3D, resources.white_tex_3d); + glTexImage3D(GL_TEXTURE_3D, 0, GL_RGB, 2, 2, 2, 0, GL_RGB, GL_UNSIGNED_BYTE, whitetexdata); + +#ifdef GLES_OVER_GL + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_BASE_LEVEL, 0); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAX_LEVEL, 0); +#endif + + glGenTextures(1, &resources.white_tex_array); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D_ARRAY, resources.white_tex_array); + glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGB, 8, 8, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); + glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 0, 8, 8, 1, GL_RGB, GL_UNSIGNED_BYTE, whitetexdata); + glGenerateMipmap(GL_TEXTURE_2D_ARRAY); + glBindTexture(GL_TEXTURE_2D, 0); +#endif } // skeleton buffer diff --git a/drivers/gles2/rasterizer_storage_gles2.h b/drivers/gles2/rasterizer_storage_gles2.h index 83697b9872..a6aae400ca 100644 --- a/drivers/gles2/rasterizer_storage_gles2.h +++ b/drivers/gles2/rasterizer_storage_gles2.h @@ -38,6 +38,7 @@ #include "shader_compiler_gles2.h" #include "shader_gles2.h" +#include "core/rid_owner.h" #include "shaders/copy.glsl.gen.h" #include "shaders/cubemap_filter.glsl.gen.h" /* @@ -71,6 +72,8 @@ public: Set<String> extensions; + bool texture_3d_supported; + bool texture_array_supported; bool float_texture_supported; bool s3tc_supported; bool etc1_supported; @@ -109,6 +112,8 @@ public: GLuint black_tex; GLuint normal_tex; GLuint aniso_tex; + GLuint white_tex_3d; + GLuint white_tex_array; GLuint mipmap_blur_fbo; GLuint mipmap_blur_color; @@ -175,7 +180,7 @@ public: //////////////////////////////////DATA/////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////// - struct Instantiable : public RID_Data { + struct Instantiable { SelfList<RasterizerScene::InstanceBase>::List instance_list; _FORCE_INLINE_ void instance_change_notify(bool p_aabb, bool p_materials) { @@ -235,7 +240,7 @@ public: struct RenderTarget; - struct Texture : RID_Data { + struct Texture { Texture *proxy; Set<Texture *> proxy_owners; @@ -336,7 +341,7 @@ public: } }; - mutable RID_Owner<Texture> texture_owner; + mutable RID_PtrOwner<Texture2D> texture_owner; Ref<Image> _get_gl_image_and_format(const Ref<Image> &p_image, Image::Format p_format, uint32_t p_flags, Image::Format &r_real_format, GLenum &r_gl_format, GLenum &r_gl_internal_format, GLenum &r_gl_type, bool &r_compressed, bool p_force_decompress) const; @@ -378,14 +383,14 @@ public: /* SKY API */ - struct Sky : public RID_Data { + struct Sky { RID panorama; GLuint radiance; int radiance_size; }; - mutable RID_Owner<Sky> sky_owner; + mutable RID_PtrOwner<Sky> sky_owner; virtual RID sky_create(); virtual void sky_set_texture(RID p_sky, RID p_panorama, int p_radiance_size); @@ -394,7 +399,7 @@ public: struct Material; - struct Shader : public RID_Data { + struct Shader { RID self; @@ -414,6 +419,7 @@ public: Map<StringName, RID> default_textures; + Vector<ShaderLanguage::DataType> texture_types; Vector<ShaderLanguage::ShaderNode::Uniform::Hint> texture_hints; bool valid; @@ -511,7 +517,7 @@ public: } }; - mutable RID_Owner<Shader> shader_owner; + mutable RID_PtrOwner<Shader> shader_owner; mutable SelfList<Shader>::List _shader_dirty_list; void _shader_make_dirty(Shader *p_shader); @@ -530,7 +536,7 @@ public: /* COMMON MATERIAL API */ - struct Material : public RID_Data { + struct Material { Shader *shader; Map<StringName, Variant> params; @@ -571,7 +577,7 @@ public: void _update_material(Material *p_material); - mutable RID_Owner<Material> material_owner; + mutable RID_PtrOwner<Material> material_owner; virtual RID material_create(); @@ -693,7 +699,7 @@ public: } }; - mutable RID_Owner<Mesh> mesh_owner; + mutable RID_PtrOwner<Mesh> mesh_owner; virtual RID mesh_create(); @@ -775,7 +781,7 @@ public: } }; - mutable RID_Owner<MultiMesh> multimesh_owner; + mutable RID_PtrOwner<MultiMesh> multimesh_owner; SelfList<MultiMesh>::List multimesh_update_list; @@ -838,7 +844,7 @@ public: Vector2 chunk_uv; Vector2 chunk_uv2; - mutable RID_Owner<Immediate> immediate_owner; + mutable RID_PtrOwner<Immediate> immediate_owner; virtual RID immediate_create(); virtual void immediate_begin(RID p_immediate, VS::PrimitiveType p_primitive, RID p_texture = RID()); @@ -856,7 +862,7 @@ public: /* SKELETON API */ - struct Skeleton : RID_Data { + struct Skeleton { bool use_2d; @@ -881,7 +887,7 @@ public: } }; - mutable RID_Owner<Skeleton> skeleton_owner; + mutable RID_PtrOwner<Skeleton> skeleton_owner; SelfList<Skeleton>::List skeleton_update_list; @@ -927,7 +933,7 @@ public: uint64_t version; }; - mutable RID_Owner<Light> light_owner; + mutable RID_PtrOwner<Light> light_owner; virtual RID light_create(VS::LightType p_type); @@ -983,7 +989,7 @@ public: int resolution; }; - mutable RID_Owner<ReflectionProbe> reflection_probe_owner; + mutable RID_PtrOwner<ReflectionProbe> reflection_probe_owner; virtual RID reflection_probe_create(); @@ -1069,7 +1075,7 @@ public: } }; - mutable RID_Owner<LightmapCapture> lightmap_capture_data_owner; + mutable RID_PtrOwner<LightmapCapture> lightmap_capture_data_owner; virtual RID lightmap_capture_create(); virtual void lightmap_capture_set_bounds(RID p_capture, const AABB &p_bounds); @@ -1132,7 +1138,7 @@ public: /* RENDER TARGET */ - struct RenderTarget : public RID_Data { + struct RenderTarget { GLuint fbo; GLuint color; GLuint depth; @@ -1228,7 +1234,7 @@ public: } }; - mutable RID_Owner<RenderTarget> render_target_owner; + mutable RID_PtrOwner<RenderTarget> render_target_owner; void _render_target_clear(RenderTarget *rt); void _render_target_allocate(RenderTarget *rt); @@ -1241,12 +1247,12 @@ public: 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); - virtual void render_target_clear_used(RID p_render_target); + virtual void render_target_set_as_unused(RID p_render_target); virtual void render_target_set_msaa(RID p_render_target, VS::ViewportMSAA p_msaa); /* CANVAS SHADOW */ - struct CanvasLightShadow : public RID_Data { + struct CanvasLightShadow { int size; int height; @@ -1255,13 +1261,13 @@ public: GLuint distance; //for older devices }; - RID_Owner<CanvasLightShadow> canvas_light_shadow_owner; + RID_PtrOwner<CanvasLightShadow> canvas_light_shadow_owner; virtual RID canvas_light_shadow_buffer_create(int p_width); /* LIGHT SHADOW MAPPING */ - struct CanvasOccluder : public RID_Data { + struct CanvasOccluder { GLuint vertex_id; // 0 means, unconfigured GLuint index_id; // 0 means, unconfigured @@ -1269,7 +1275,7 @@ public: int len; }; - RID_Owner<CanvasOccluder> canvas_occluder_owner; + RID_PtrOwner<CanvasOccluder> canvas_occluder_owner; virtual RID canvas_light_occluder_create(); virtual void canvas_light_occluder_set_polylines(RID p_occluder, const PoolVector<Vector2> &p_lines); diff --git a/drivers/gles2/shader_compiler_gles2.cpp b/drivers/gles2/shader_compiler_gles2.cpp index 5dec6f2fee..620fcdbdca 100644 --- a/drivers/gles2/shader_compiler_gles2.cpp +++ b/drivers/gles2/shader_compiler_gles2.cpp @@ -240,21 +240,20 @@ void ShaderCompilerGLES2::_dump_function_deps(SL::ShaderNode *p_node, const Stri r_to_add += "\n"; StringBuffer<128> header; - - header += _typestr(fnode->return_type); - header += " "; - header += _mkid(fnode->name); - header += "("; + if (fnode->return_type == SL::TYPE_STRUCT) { + header += _mkid(fnode->return_struct_name) + " " + _mkid(fnode->name) + "("; + } else { + header += _typestr(fnode->return_type) + " " + _mkid(fnode->name) + "("; + } for (int i = 0; i < fnode->arguments.size(); i++) { if (i > 0) header += ", "; - - header += _qualstr(fnode->arguments[i].qualifier); - header += _prestr(fnode->arguments[i].precision); - header += _typestr(fnode->arguments[i].type); - header += " "; - header += _mkid(fnode->arguments[i].name); + if (fnode->arguments[i].type == SL::TYPE_STRUCT) { + header += _qualstr(fnode->arguments[i].qualifier) + _mkid(fnode->arguments[i].type_str) + " " + _mkid(fnode->arguments[i].name); + } else { + header += _qualstr(fnode->arguments[i].qualifier) + _prestr(fnode->arguments[i].precision) + _typestr(fnode->arguments[i].type) + " " + _mkid(fnode->arguments[i].name); + } } header += ")\n"; @@ -305,12 +304,48 @@ String ShaderCompilerGLES2::_dump_node_code(SL::Node *p_node, int p_level, Gener r_gen_code.texture_uniforms.resize(max_texture_uniforms); r_gen_code.texture_hints.resize(max_texture_uniforms); + r_gen_code.texture_types.resize(max_texture_uniforms); r_gen_code.uniforms.resize(max_uniforms + max_texture_uniforms); StringBuilder vertex_global; StringBuilder fragment_global; + // structs + + for (int i = 0; i < snode->vstructs.size(); i++) { + + SL::StructNode *st = snode->vstructs[i].shader_struct; + String struct_code; + + struct_code += "struct "; + struct_code += _mkid(snode->vstructs[i].name); + struct_code += " "; + struct_code += "{\n"; + for (int j = 0; j < st->members.size(); j++) { + SL::MemberNode *m = st->members[j]; + if (m->datatype == SL::TYPE_STRUCT) { + struct_code += _mkid(m->struct_name); + } else { + struct_code += _prestr(m->precision); + struct_code += _typestr(m->datatype); + } + struct_code += " "; + struct_code += m->name; + if (m->array_size > 0) { + struct_code += "["; + struct_code += itos(m->array_size); + struct_code += "]"; + } + struct_code += ";\n"; + } + struct_code += "}"; + struct_code += ";\n"; + + vertex_global += struct_code; + fragment_global += struct_code; + } + // uniforms for (Map<StringName, SL::ShaderNode::Uniform>::Element *E = snode->uniforms.front(); E; E = E->next()) { @@ -332,6 +367,7 @@ String ShaderCompilerGLES2::_dump_node_code(SL::Node *p_node, int p_level, Gener if (SL::is_sampler_type(E->get().type)) { r_gen_code.texture_uniforms.write[E->get().texture_order] = E->key(); r_gen_code.texture_hints.write[E->get().texture_order] = E->get().hint; + r_gen_code.texture_types.write[E->get().texture_order] = E->get().type; } else { r_gen_code.uniforms.write[E->get().order] = E->key(); } @@ -372,7 +408,11 @@ String ShaderCompilerGLES2::_dump_node_code(SL::Node *p_node, int p_level, Gener String gcode; gcode += "const "; gcode += _prestr(E->get().precision); - gcode += _typestr(E->get().type); + if (E->get().type == SL::TYPE_STRUCT) { + gcode += _mkid(E->get().type_str); + } else { + gcode += _typestr(E->get().type); + } gcode += " " + _mkid(E->key()); gcode += "="; gcode += _dump_node_code(E->get().initializer, p_level, r_gen_code, p_actions, p_default_actions, p_assigning); @@ -418,7 +458,9 @@ String ShaderCompilerGLES2::_dump_node_code(SL::Node *p_node, int p_level, Gener r_gen_code.fragment_global = fragment_global.as_string(); } break; + case SL::Node::TYPE_STRUCT: { + } break; case SL::Node::TYPE_FUNCTION: { } break; @@ -457,8 +499,12 @@ String ShaderCompilerGLES2::_dump_node_code(SL::Node *p_node, int p_level, Gener if (var_dec_node->is_const) { declaration += "const "; } - declaration += _prestr(var_dec_node->precision); - declaration += _typestr(var_dec_node->datatype); + if (var_dec_node->datatype == SL::TYPE_STRUCT) { + declaration += _mkid(var_dec_node->struct_name); + } else { + declaration += _prestr(var_dec_node->precision); + declaration += _typestr(var_dec_node->datatype); + } for (int i = 0; i < var_dec_node->declarations.size(); i++) { @@ -517,14 +563,37 @@ String ShaderCompilerGLES2::_dump_node_code(SL::Node *p_node, int p_level, Gener } } } break; + case SL::Node::TYPE_ARRAY_CONSTRUCT: { + SL::ArrayConstructNode *arr_con_node = (SL::ArrayConstructNode *)p_node; + int sz = arr_con_node->initializer.size(); + if (acnode->datatype == SL::TYPE_STRUCT) { + code += _mkid(arr_con_node->struct_name); + } else { + code += _typestr(arr_con_node->datatype); + } + code += "["; + code += itos(arr_con_node->initializer.size()); + code += "]"; + code += "("; + for (int i = 0; i < sz; i++) { + code += _dump_node_code(arr_con_node->initializer[i], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); + if (i != sz - 1) { + code += ", "; + } + } + code += ")"; + } break; case SL::Node::TYPE_ARRAY_DECLARATION: { SL::ArrayDeclarationNode *arr_dec_node = (SL::ArrayDeclarationNode *)p_node; StringBuffer<> declaration; - declaration += _prestr(arr_dec_node->precision); - declaration += _typestr(arr_dec_node->datatype); - + if (arr_dec_node->datatype == SL::TYPE_STRUCT) { + declaration += _mkid(arr_dec_node->struct_name); + } else { + declaration += _prestr(arr_dec_node->precision); + declaration += _typestr(arr_dec_node->datatype); + } for (int i = 0; i < arr_dec_node->declarations.size(); i++) { if (i > 0) { @@ -644,12 +713,14 @@ String ShaderCompilerGLES2::_dump_node_code(SL::Node *p_node, int p_level, Gener } break; case SL::OP_CALL: + case SL::OP_STRUCT: case SL::OP_CONSTRUCT: { ERR_FAIL_COND_V(op_node->arguments[0]->type != SL::Node::TYPE_VARIABLE, String()); SL::VariableNode *var_node = (SL::VariableNode *)op_node->arguments[0]; - - if (op_node->op == SL::OP_CONSTRUCT) { + if (op_node->op == SL::OP_STRUCT) { + code += _mkid(var_node->name); + } else if (op_node->op == SL::OP_CONSTRUCT) { code += var_node->name; } else { @@ -660,6 +731,10 @@ String ShaderCompilerGLES2::_dump_node_code(SL::Node *p_node, int p_level, Gener code += "texture2D"; } else if (op_node->arguments[1]->get_datatype() == SL::TYPE_SAMPLERCUBE) { code += "textureCube"; + } else if (op_node->arguments[1]->get_datatype() == SL::TYPE_SAMPLER3D) { + code += "texture3D"; + } else if (op_node->arguments[1]->get_datatype() == SL::TYPE_SAMPLER2DARRAY) { + code += "texture2DArray"; } } else if (var_node->name == "textureLod") { @@ -669,6 +744,10 @@ String ShaderCompilerGLES2::_dump_node_code(SL::Node *p_node, int p_level, Gener code += "texture2DLod"; } else if (op_node->arguments[1]->get_datatype() == SL::TYPE_SAMPLERCUBE) { code += "textureCubeLod"; + } else if (op_node->arguments[1]->get_datatype() == SL::TYPE_SAMPLER3D) { + code += "texture3DLod"; + } else if (op_node->arguments[1]->get_datatype() == SL::TYPE_SAMPLER2DARRAY) { + code += "texture2DArrayLod"; } } else if (var_node->name == "mix") { @@ -844,6 +923,11 @@ String ShaderCompilerGLES2::_dump_node_code(SL::Node *p_node, int p_level, Gener code += _dump_node_code(member_node->owner, p_level, r_gen_code, p_actions, p_default_actions, p_assigning); code += "."; code += member_node->name; + if (member_node->index_expression != NULL) { + code += "["; + code += _dump_node_code(member_node->index_expression, p_level, r_gen_code, p_actions, p_default_actions, p_assigning); + code += "]"; + } } break; } @@ -869,6 +953,7 @@ Error ShaderCompilerGLES2::compile(VS::ShaderMode p_mode, const String &p_code, r_gen_code.uniforms.clear(); r_gen_code.texture_uniforms.clear(); r_gen_code.texture_hints.clear(); + r_gen_code.texture_types.clear(); r_gen_code.vertex = String(); r_gen_code.vertex_global = String(); r_gen_code.fragment = String(); diff --git a/drivers/gles2/shader_compiler_gles2.h b/drivers/gles2/shader_compiler_gles2.h index 683c8bf3c4..e39ef5e7bd 100644 --- a/drivers/gles2/shader_compiler_gles2.h +++ b/drivers/gles2/shader_compiler_gles2.h @@ -54,6 +54,7 @@ public: Vector<CharString> custom_defines; Vector<StringName> uniforms; Vector<StringName> texture_uniforms; + Vector<ShaderLanguage::DataType> texture_types; Vector<ShaderLanguage::ShaderNode::Uniform::Hint> texture_hints; String vertex_global; @@ -98,4 +99,4 @@ public: ShaderCompilerGLES2(); }; -#endif // SHADERCOMPILERGLES3_H +#endif // SHADERCOMPILERGLES2_H diff --git a/drivers/gles2/shader_gles2.cpp b/drivers/gles2/shader_gles2.cpp index 8bb1ef7f0f..f03f1ffa4f 100644 --- a/drivers/gles2/shader_gles2.cpp +++ b/drivers/gles2/shader_gles2.cpp @@ -126,7 +126,7 @@ static void _display_error_with_code(const String &p_error, const Vector<const c line++; } - ERR_PRINTS(p_error); + ERR_PRINT(p_error); } static String _mkid(const String &p_id) { diff --git a/drivers/gles2/shaders/canvas.glsl b/drivers/gles2/shaders/canvas.glsl index afce403a9f..3b685b3f0b 100644 --- a/drivers/gles2/shaders/canvas.glsl +++ b/drivers/gles2/shaders/canvas.glsl @@ -10,6 +10,12 @@ precision highp float; precision highp int; #endif +#ifndef USE_GLES_OVER_GL +#extension GL_OES_texture_3D : enable +#else +#extension GL_EXT_texture_array : enable +#endif + uniform highp mat4 projection_matrix; /* clang-format on */ @@ -229,6 +235,12 @@ VERTEX_SHADER_CODE /* clang-format off */ [fragment] +#ifndef USE_GLES_OVER_GL +#extension GL_OES_texture_3D : enable +#else +#extension GL_EXT_texture_array : enable +#endif + // texture2DLodEXT and textureCubeLodEXT are fragment shader specific. // Do not copy these defines in the vertex section. #ifndef USE_GLES_OVER_GL diff --git a/drivers/gles2/shaders/scene.glsl b/drivers/gles2/shaders/scene.glsl index ac7a8796a3..84aadcbbc3 100644 --- a/drivers/gles2/shaders/scene.glsl +++ b/drivers/gles2/shaders/scene.glsl @@ -10,6 +10,12 @@ precision highp float; precision highp int; #endif +#ifndef USE_GLES_OVER_GL +#extension GL_OES_texture_3D : enable +#else +#extension GL_EXT_texture_array : enable +#endif + /* clang-format on */ #include "stdlib.glsl" /* clang-format off */ @@ -672,6 +678,12 @@ VERTEX_SHADER_CODE /* clang-format off */ [fragment] +#ifndef USE_GLES_OVER_GL +#extension GL_OES_texture_3D : enable +#else +#extension GL_EXT_texture_array : enable +#endif + // texture2DLodEXT and textureCubeLodEXT are fragment shader specific. // Do not copy these defines in the vertex section. #ifndef USE_GLES_OVER_GL diff --git a/drivers/gles3/SCsub b/drivers/gles3/SCsub deleted file mode 100644 index 2471dd3739..0000000000 --- a/drivers/gles3/SCsub +++ /dev/null @@ -1,7 +0,0 @@ -#!/usr/bin/env python - -Import('env') - -env.add_source_files(env.drivers_sources,"*.cpp") - -SConscript("shaders/SCsub") diff --git a/drivers/gles3/rasterizer_canvas_gles3.cpp b/drivers/gles3/rasterizer_canvas_gles3.cpp deleted file mode 100644 index b7b31c66aa..0000000000 --- a/drivers/gles3/rasterizer_canvas_gles3.cpp +++ /dev/null @@ -1,2263 +0,0 @@ -/*************************************************************************/ -/* rasterizer_canvas_gles3.cpp */ -/*************************************************************************/ -/* 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. */ -/*************************************************************************/ - -#include "rasterizer_canvas_gles3.h" - -#include "core/os/os.h" -#include "core/project_settings.h" -#include "rasterizer_scene_gles3.h" -#include "servers/visual/visual_server_raster.h" - -#ifndef GLES_OVER_GL -#define glClearDepth glClearDepthf -#endif - -static _FORCE_INLINE_ void store_transform2d(const Transform2D &p_mtx, float *p_array) { - - p_array[0] = p_mtx.elements[0][0]; - p_array[1] = p_mtx.elements[0][1]; - p_array[2] = 0; - p_array[3] = 0; - p_array[4] = p_mtx.elements[1][0]; - p_array[5] = p_mtx.elements[1][1]; - p_array[6] = 0; - p_array[7] = 0; - p_array[8] = 0; - p_array[9] = 0; - p_array[10] = 1; - p_array[11] = 0; - p_array[12] = p_mtx.elements[2][0]; - p_array[13] = p_mtx.elements[2][1]; - p_array[14] = 0; - p_array[15] = 1; -} - -static _FORCE_INLINE_ void store_transform(const Transform &p_mtx, float *p_array) { - p_array[0] = p_mtx.basis.elements[0][0]; - p_array[1] = p_mtx.basis.elements[1][0]; - p_array[2] = p_mtx.basis.elements[2][0]; - p_array[3] = 0; - p_array[4] = p_mtx.basis.elements[0][1]; - p_array[5] = p_mtx.basis.elements[1][1]; - p_array[6] = p_mtx.basis.elements[2][1]; - p_array[7] = 0; - p_array[8] = p_mtx.basis.elements[0][2]; - p_array[9] = p_mtx.basis.elements[1][2]; - p_array[10] = p_mtx.basis.elements[2][2]; - p_array[11] = 0; - p_array[12] = p_mtx.origin.x; - p_array[13] = p_mtx.origin.y; - p_array[14] = p_mtx.origin.z; - p_array[15] = 1; -} - -static _FORCE_INLINE_ void store_camera(const CameraMatrix &p_mtx, float *p_array) { - - for (int i = 0; i < 4; i++) { - for (int j = 0; j < 4; j++) { - - p_array[i * 4 + j] = p_mtx.matrix[i][j]; - } - } -} - -RID RasterizerCanvasGLES3::light_internal_create() { - - LightInternal *li = memnew(LightInternal); - - glGenBuffers(1, &li->ubo); - glBindBuffer(GL_UNIFORM_BUFFER, li->ubo); - glBufferData(GL_UNIFORM_BUFFER, sizeof(LightInternal::UBOData), &state.canvas_item_ubo_data, GL_DYNAMIC_DRAW); - glBindBuffer(GL_UNIFORM_BUFFER, 0); - - return light_internal_owner.make_rid(li); -} - -void RasterizerCanvasGLES3::light_internal_update(RID p_rid, Light *p_light) { - - LightInternal *li = light_internal_owner.getornull(p_rid); - ERR_FAIL_COND(!li); - - store_transform2d(p_light->light_shader_xform, li->ubo_data.light_matrix); - store_transform2d(p_light->xform_cache.affine_inverse(), li->ubo_data.local_matrix); - store_camera(p_light->shadow_matrix_cache, li->ubo_data.shadow_matrix); - - for (int i = 0; i < 4; i++) { - - li->ubo_data.color[i] = p_light->color[i] * p_light->energy; - li->ubo_data.shadow_color[i] = p_light->shadow_color[i]; - } - - li->ubo_data.light_pos[0] = p_light->light_shader_pos.x; - li->ubo_data.light_pos[1] = p_light->light_shader_pos.y; - li->ubo_data.shadowpixel_size = (1.0 / p_light->shadow_buffer_size) * (1.0 + p_light->shadow_smooth); - li->ubo_data.light_outside_alpha = p_light->mode == VS::CANVAS_LIGHT_MODE_MASK ? 1.0 : 0.0; - li->ubo_data.light_height = p_light->height; - if (p_light->radius_cache == 0) - li->ubo_data.shadow_gradient = 0; - else - li->ubo_data.shadow_gradient = p_light->shadow_gradient_length / (p_light->radius_cache * 1.1); - - li->ubo_data.shadow_distance_mult = (p_light->radius_cache * 1.1); - - glBindBuffer(GL_UNIFORM_BUFFER, li->ubo); - glBufferData(GL_UNIFORM_BUFFER, sizeof(LightInternal::UBOData), &li->ubo_data, GL_DYNAMIC_DRAW); - glBindBuffer(GL_UNIFORM_BUFFER, 0); -} - -void RasterizerCanvasGLES3::light_internal_free(RID p_rid) { - - LightInternal *li = light_internal_owner.getornull(p_rid); - ERR_FAIL_COND(!li); - - glDeleteBuffers(1, &li->ubo); - light_internal_owner.free(p_rid); - memdelete(li); -} - -void RasterizerCanvasGLES3::canvas_begin() { - - if (storage->frame.current_rt && storage->frame.clear_request) { - // a clear request may be pending, so do it - bool transparent = storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]; - - glClearColor(storage->frame.clear_request_color.r, - storage->frame.clear_request_color.g, - storage->frame.clear_request_color.b, - transparent ? storage->frame.clear_request_color.a : 1.0); - glClear(GL_COLOR_BUFFER_BIT); - storage->frame.clear_request = false; - glColorMask(1, 1, 1, transparent ? 1 : 0); - } - - reset_canvas(); - - state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_TEXTURE_RECT, true); - state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_LIGHTING, false); - state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_SHADOWS, false); - state.canvas_shader.set_conditional(CanvasShaderGLES3::SHADOW_FILTER_NEAREST, false); - state.canvas_shader.set_conditional(CanvasShaderGLES3::SHADOW_FILTER_PCF3, false); - state.canvas_shader.set_conditional(CanvasShaderGLES3::SHADOW_FILTER_PCF5, false); - state.canvas_shader.set_conditional(CanvasShaderGLES3::SHADOW_FILTER_PCF7, false); - state.canvas_shader.set_conditional(CanvasShaderGLES3::SHADOW_FILTER_PCF9, false); - state.canvas_shader.set_conditional(CanvasShaderGLES3::SHADOW_FILTER_PCF13, false); - state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_DISTANCE_FIELD, false); - state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_NINEPATCH, false); - state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_SKELETON, false); - - state.canvas_shader.set_custom_shader(0); - state.canvas_shader.bind(); - state.canvas_shader.set_uniform(CanvasShaderGLES3::FINAL_MODULATE, Color(1, 1, 1, 1)); - state.canvas_shader.set_uniform(CanvasShaderGLES3::MODELVIEW_MATRIX, Transform2D()); - state.canvas_shader.set_uniform(CanvasShaderGLES3::EXTRA_MATRIX, Transform2D()); - if (storage->frame.current_rt) { - state.canvas_shader.set_uniform(CanvasShaderGLES3::SCREEN_PIXEL_SIZE, Vector2(1.0 / storage->frame.current_rt->width, 1.0 / storage->frame.current_rt->height)); - } else { - state.canvas_shader.set_uniform(CanvasShaderGLES3::SCREEN_PIXEL_SIZE, Vector2(1.0, 1.0)); - } - - //state.canvas_shader.set_uniform(CanvasShaderGLES3::PROJECTION_MATRIX,state.vp); - //state.canvas_shader.set_uniform(CanvasShaderGLES3::MODELVIEW_MATRIX,Transform()); - //state.canvas_shader.set_uniform(CanvasShaderGLES3::EXTRA_MATRIX,Transform()); - - glBindBufferBase(GL_UNIFORM_BUFFER, 0, state.canvas_item_ubo); - glBindVertexArray(data.canvas_quad_array); - state.using_texture_rect = true; - state.using_ninepatch = false; - state.using_skeleton = false; -} - -void RasterizerCanvasGLES3::canvas_end() { - - glBindVertexArray(0); - glBindBufferBase(GL_UNIFORM_BUFFER, 0, 0); - glColorMask(1, 1, 1, 1); - - glVertexAttrib4f(VS::ARRAY_COLOR, 1, 1, 1, 1); - - state.using_texture_rect = false; - state.using_ninepatch = false; -} - -RasterizerStorageGLES3::Texture *RasterizerCanvasGLES3::_bind_canvas_texture(const RID &p_texture, const RID &p_normal_map, bool p_force) { - - RasterizerStorageGLES3::Texture *tex_return = NULL; - - if (p_texture == state.current_tex && !p_force) { - tex_return = state.current_tex_ptr; - } else if (p_texture.is_valid()) { - - RasterizerStorageGLES3::Texture *texture = storage->texture_owner.getornull(p_texture); - - if (!texture) { - state.current_tex = RID(); - state.current_tex_ptr = NULL; - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, storage->resources.white_tex); - - } else { - - if (texture->redraw_if_visible) { //check before proxy, because this is usually used with proxies - VisualServerRaster::redraw_request(); - } - - texture = texture->get_ptr(); - - if (texture->render_target) - texture->render_target->used_in_frame = true; - - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, texture->tex_id); - state.current_tex = p_texture; - state.current_tex_ptr = texture; - - tex_return = texture; - } - - } else { - - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, storage->resources.white_tex); - state.current_tex = RID(); - state.current_tex_ptr = NULL; - } - - if (p_normal_map == state.current_normal && !p_force) { - //do none - state.canvas_shader.set_uniform(CanvasShaderGLES3::USE_DEFAULT_NORMAL, state.current_normal.is_valid()); - - } else if (p_normal_map.is_valid()) { - - RasterizerStorageGLES3::Texture *normal_map = storage->texture_owner.getornull(p_normal_map); - - if (!normal_map) { - state.current_normal = RID(); - glActiveTexture(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_2D, storage->resources.normal_tex); - state.canvas_shader.set_uniform(CanvasShaderGLES3::USE_DEFAULT_NORMAL, false); - - } else { - - if (normal_map->redraw_if_visible) { //check before proxy, because this is usually used with proxies - VisualServerRaster::redraw_request(); - } - - normal_map = normal_map->get_ptr(); - - glActiveTexture(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_2D, normal_map->tex_id); - state.current_normal = p_normal_map; - state.canvas_shader.set_uniform(CanvasShaderGLES3::USE_DEFAULT_NORMAL, true); - } - - } else { - - state.current_normal = RID(); - glActiveTexture(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_2D, storage->resources.normal_tex); - state.canvas_shader.set_uniform(CanvasShaderGLES3::USE_DEFAULT_NORMAL, false); - } - - return tex_return; -} - -void RasterizerCanvasGLES3::_set_texture_rect_mode(bool p_enable, bool p_ninepatch) { - - if (state.using_texture_rect == p_enable && state.using_ninepatch == p_ninepatch) - return; - - if (p_enable) { - glBindVertexArray(data.canvas_quad_array); - - } else { - glBindVertexArray(0); - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - } - - state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_NINEPATCH, p_ninepatch && p_enable); - state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_TEXTURE_RECT, p_enable); - state.canvas_shader.bind(); - state.canvas_shader.set_uniform(CanvasShaderGLES3::FINAL_MODULATE, state.canvas_item_modulate); - state.canvas_shader.set_uniform(CanvasShaderGLES3::MODELVIEW_MATRIX, state.final_transform); - state.canvas_shader.set_uniform(CanvasShaderGLES3::EXTRA_MATRIX, state.extra_matrix); - if (state.using_skeleton) { - state.canvas_shader.set_uniform(CanvasShaderGLES3::SKELETON_TRANSFORM, state.skeleton_transform); - state.canvas_shader.set_uniform(CanvasShaderGLES3::SKELETON_TRANSFORM_INVERSE, state.skeleton_transform_inverse); - } - if (storage->frame.current_rt) { - state.canvas_shader.set_uniform(CanvasShaderGLES3::SCREEN_PIXEL_SIZE, Vector2(1.0 / storage->frame.current_rt->width, 1.0 / storage->frame.current_rt->height)); - } else { - state.canvas_shader.set_uniform(CanvasShaderGLES3::SCREEN_PIXEL_SIZE, Vector2(1.0, 1.0)); - } - state.using_texture_rect = p_enable; - state.using_ninepatch = p_ninepatch; -} - -void RasterizerCanvasGLES3::_draw_polygon(const int *p_indices, int p_index_count, int p_vertex_count, const Vector2 *p_vertices, const Vector2 *p_uvs, const Color *p_colors, bool p_singlecolor, const int *p_bones, const float *p_weights) { - - glBindVertexArray(data.polygon_buffer_pointer_array); - glBindBuffer(GL_ARRAY_BUFFER, data.polygon_buffer); - -#ifndef GLES_OVER_GL - // Orphan the buffer to avoid CPU/GPU sync points caused by glBufferSubData - glBufferData(GL_ARRAY_BUFFER, data.polygon_buffer_size, NULL, GL_DYNAMIC_DRAW); -#endif - - uint32_t buffer_ofs = 0; - - //vertex - glBufferSubData(GL_ARRAY_BUFFER, buffer_ofs, sizeof(Vector2) * p_vertex_count, p_vertices); - glEnableVertexAttribArray(VS::ARRAY_VERTEX); - glVertexAttribPointer(VS::ARRAY_VERTEX, 2, GL_FLOAT, false, sizeof(Vector2), CAST_INT_TO_UCHAR_PTR(buffer_ofs)); - buffer_ofs += sizeof(Vector2) * p_vertex_count; - //color -#ifdef DEBUG_ENABLED - ERR_FAIL_COND(buffer_ofs > data.polygon_buffer_size); -#endif - - if (p_singlecolor) { - glDisableVertexAttribArray(VS::ARRAY_COLOR); - Color m = *p_colors; - glVertexAttrib4f(VS::ARRAY_COLOR, m.r, m.g, m.b, m.a); - } else if (!p_colors) { - glDisableVertexAttribArray(VS::ARRAY_COLOR); - glVertexAttrib4f(VS::ARRAY_COLOR, 1, 1, 1, 1); - } else { - - glBufferSubData(GL_ARRAY_BUFFER, buffer_ofs, sizeof(Color) * p_vertex_count, p_colors); - glEnableVertexAttribArray(VS::ARRAY_COLOR); - glVertexAttribPointer(VS::ARRAY_COLOR, 4, GL_FLOAT, false, sizeof(Color), CAST_INT_TO_UCHAR_PTR(buffer_ofs)); - buffer_ofs += sizeof(Color) * p_vertex_count; - } - -#ifdef DEBUG_ENABLED - ERR_FAIL_COND(buffer_ofs > data.polygon_buffer_size); -#endif - - if (p_uvs) { - - glBufferSubData(GL_ARRAY_BUFFER, buffer_ofs, sizeof(Vector2) * p_vertex_count, p_uvs); - glEnableVertexAttribArray(VS::ARRAY_TEX_UV); - glVertexAttribPointer(VS::ARRAY_TEX_UV, 2, GL_FLOAT, false, sizeof(Vector2), CAST_INT_TO_UCHAR_PTR(buffer_ofs)); - buffer_ofs += sizeof(Vector2) * p_vertex_count; - - } else { - glDisableVertexAttribArray(VS::ARRAY_TEX_UV); - } - -#ifdef DEBUG_ENABLED - ERR_FAIL_COND(buffer_ofs > data.polygon_buffer_size); -#endif - - if (p_bones && p_weights) { - - glBufferSubData(GL_ARRAY_BUFFER, buffer_ofs, sizeof(int) * 4 * p_vertex_count, p_bones); - glEnableVertexAttribArray(VS::ARRAY_BONES); - //glVertexAttribPointer(VS::ARRAY_BONES, 4, GL_UNSIGNED_INT, false, sizeof(int) * 4, ((uint8_t *)0) + buffer_ofs); - glVertexAttribIPointer(VS::ARRAY_BONES, 4, GL_UNSIGNED_INT, sizeof(int) * 4, CAST_INT_TO_UCHAR_PTR(buffer_ofs)); - buffer_ofs += sizeof(int) * 4 * p_vertex_count; - - glBufferSubData(GL_ARRAY_BUFFER, buffer_ofs, sizeof(float) * 4 * p_vertex_count, p_weights); - glEnableVertexAttribArray(VS::ARRAY_WEIGHTS); - glVertexAttribPointer(VS::ARRAY_WEIGHTS, 4, GL_FLOAT, false, sizeof(float) * 4, CAST_INT_TO_UCHAR_PTR(buffer_ofs)); - buffer_ofs += sizeof(float) * 4 * p_vertex_count; - - } else if (state.using_skeleton) { - glVertexAttribI4ui(VS::ARRAY_BONES, 0, 0, 0, 0); - glVertexAttrib4f(VS::ARRAY_WEIGHTS, 0, 0, 0, 0); - } - -#ifdef DEBUG_ENABLED - ERR_FAIL_COND(buffer_ofs > data.polygon_buffer_size); -#endif - - //bind the indices buffer. - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, data.polygon_index_buffer); -#ifndef GLES_OVER_GL - // Orphan the buffer to avoid CPU/GPU sync points caused by glBufferSubData - glBufferData(GL_ELEMENT_ARRAY_BUFFER, data.polygon_index_buffer_size, NULL, GL_DYNAMIC_DRAW); -#endif - glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, sizeof(int) * p_index_count, p_indices); - - //draw the triangles. - glDrawElements(GL_TRIANGLES, p_index_count, GL_UNSIGNED_INT, 0); - - storage->frame.canvas_draw_commands++; - - if (p_bones && p_weights) { - //not used so often, so disable when used - glDisableVertexAttribArray(VS::ARRAY_BONES); - glDisableVertexAttribArray(VS::ARRAY_WEIGHTS); - } - - glBindVertexArray(0); - glBindBuffer(GL_ARRAY_BUFFER, 0); -} - -void RasterizerCanvasGLES3::_draw_generic(GLuint p_primitive, int p_vertex_count, const Vector2 *p_vertices, const Vector2 *p_uvs, const Color *p_colors, bool p_singlecolor) { - - glBindVertexArray(data.polygon_buffer_pointer_array); - glBindBuffer(GL_ARRAY_BUFFER, data.polygon_buffer); - -#ifndef GLES_OVER_GL - // Orphan the buffer to avoid CPU/GPU sync points caused by glBufferSubData - glBufferData(GL_ARRAY_BUFFER, data.polygon_buffer_size, NULL, GL_DYNAMIC_DRAW); -#endif - - uint32_t buffer_ofs = 0; - - //vertex - glBufferSubData(GL_ARRAY_BUFFER, buffer_ofs, sizeof(Vector2) * p_vertex_count, p_vertices); - glEnableVertexAttribArray(VS::ARRAY_VERTEX); - glVertexAttribPointer(VS::ARRAY_VERTEX, 2, GL_FLOAT, false, sizeof(Vector2), CAST_INT_TO_UCHAR_PTR(buffer_ofs)); - buffer_ofs += sizeof(Vector2) * p_vertex_count; - //color - - if (p_singlecolor) { - glDisableVertexAttribArray(VS::ARRAY_COLOR); - Color m = *p_colors; - glVertexAttrib4f(VS::ARRAY_COLOR, m.r, m.g, m.b, m.a); - } else if (!p_colors) { - glDisableVertexAttribArray(VS::ARRAY_COLOR); - glVertexAttrib4f(VS::ARRAY_COLOR, 1, 1, 1, 1); - } else { - - glBufferSubData(GL_ARRAY_BUFFER, buffer_ofs, sizeof(Color) * p_vertex_count, p_colors); - glEnableVertexAttribArray(VS::ARRAY_COLOR); - glVertexAttribPointer(VS::ARRAY_COLOR, 4, GL_FLOAT, false, sizeof(Color), CAST_INT_TO_UCHAR_PTR(buffer_ofs)); - buffer_ofs += sizeof(Color) * p_vertex_count; - } - - if (p_uvs) { - - glBufferSubData(GL_ARRAY_BUFFER, buffer_ofs, sizeof(Vector2) * p_vertex_count, p_uvs); - glEnableVertexAttribArray(VS::ARRAY_TEX_UV); - glVertexAttribPointer(VS::ARRAY_TEX_UV, 2, GL_FLOAT, false, sizeof(Vector2), CAST_INT_TO_UCHAR_PTR(buffer_ofs)); - buffer_ofs += sizeof(Vector2) * p_vertex_count; - - } else { - glDisableVertexAttribArray(VS::ARRAY_TEX_UV); - } - - glDrawArrays(p_primitive, 0, p_vertex_count); - - storage->frame.canvas_draw_commands++; - - glBindVertexArray(0); - glBindBuffer(GL_ARRAY_BUFFER, 0); -} - -void RasterizerCanvasGLES3::_draw_generic_indices(GLuint p_primitive, const int *p_indices, int p_index_count, int p_vertex_count, const Vector2 *p_vertices, const Vector2 *p_uvs, const Color *p_colors, bool p_singlecolor) { - - glBindVertexArray(data.polygon_buffer_pointer_array); - glBindBuffer(GL_ARRAY_BUFFER, data.polygon_buffer); - -#ifndef GLES_OVER_GL - // Orphan the buffer to avoid CPU/GPU sync points caused by glBufferSubData - glBufferData(GL_ARRAY_BUFFER, data.polygon_buffer_size, NULL, GL_DYNAMIC_DRAW); -#endif - - uint32_t buffer_ofs = 0; - - //vertex - glBufferSubData(GL_ARRAY_BUFFER, buffer_ofs, sizeof(Vector2) * p_vertex_count, p_vertices); - glEnableVertexAttribArray(VS::ARRAY_VERTEX); - glVertexAttribPointer(VS::ARRAY_VERTEX, 2, GL_FLOAT, false, sizeof(Vector2), CAST_INT_TO_UCHAR_PTR(buffer_ofs)); - buffer_ofs += sizeof(Vector2) * p_vertex_count; - //color -#ifdef DEBUG_ENABLED - ERR_FAIL_COND(buffer_ofs > data.polygon_buffer_size); -#endif - - if (p_singlecolor) { - glDisableVertexAttribArray(VS::ARRAY_COLOR); - Color m = *p_colors; - glVertexAttrib4f(VS::ARRAY_COLOR, m.r, m.g, m.b, m.a); - } else if (!p_colors) { - glDisableVertexAttribArray(VS::ARRAY_COLOR); - glVertexAttrib4f(VS::ARRAY_COLOR, 1, 1, 1, 1); - } else { - - glBufferSubData(GL_ARRAY_BUFFER, buffer_ofs, sizeof(Color) * p_vertex_count, p_colors); - glEnableVertexAttribArray(VS::ARRAY_COLOR); - glVertexAttribPointer(VS::ARRAY_COLOR, 4, GL_FLOAT, false, sizeof(Color), CAST_INT_TO_UCHAR_PTR(buffer_ofs)); - buffer_ofs += sizeof(Color) * p_vertex_count; - } - -#ifdef DEBUG_ENABLED - ERR_FAIL_COND(buffer_ofs > data.polygon_buffer_size); -#endif - - if (p_uvs) { - - glBufferSubData(GL_ARRAY_BUFFER, buffer_ofs, sizeof(Vector2) * p_vertex_count, p_uvs); - glEnableVertexAttribArray(VS::ARRAY_TEX_UV); - glVertexAttribPointer(VS::ARRAY_TEX_UV, 2, GL_FLOAT, false, sizeof(Vector2), CAST_INT_TO_UCHAR_PTR(buffer_ofs)); - buffer_ofs += sizeof(Vector2) * p_vertex_count; - - } else { - glDisableVertexAttribArray(VS::ARRAY_TEX_UV); - } - -#ifdef DEBUG_ENABLED - ERR_FAIL_COND(buffer_ofs > data.polygon_buffer_size); -#endif - - //bind the indices buffer. - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, data.polygon_index_buffer); -#ifndef GLES_OVER_GL - // Orphan the buffer to avoid CPU/GPU sync points caused by glBufferSubData - glBufferData(GL_ELEMENT_ARRAY_BUFFER, data.polygon_index_buffer_size, NULL, GL_DYNAMIC_DRAW); -#endif - glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, sizeof(int) * p_index_count, p_indices); - - //draw the triangles. - glDrawElements(p_primitive, p_index_count, GL_UNSIGNED_INT, 0); - - storage->frame.canvas_draw_commands++; - - glBindVertexArray(0); - glBindBuffer(GL_ARRAY_BUFFER, 0); -} - -void RasterizerCanvasGLES3::_draw_gui_primitive(int p_points, const Vector2 *p_vertices, const Color *p_colors, const Vector2 *p_uvs) { - - static const GLenum prim[5] = { GL_POINTS, GL_POINTS, GL_LINES, GL_TRIANGLES, GL_TRIANGLE_FAN }; - - //#define GLES_USE_PRIMITIVE_BUFFER - - int version = 0; - int color_ofs = 0; - int uv_ofs = 0; - int stride = 2; - - if (p_colors) { //color - version |= 1; - color_ofs = stride; - stride += 4; - } - - if (p_uvs) { //uv - version |= 2; - uv_ofs = stride; - stride += 2; - } - - float b[(2 + 2 + 4) * 4]; - - for (int i = 0; i < p_points; i++) { - b[stride * i + 0] = p_vertices[i].x; - b[stride * i + 1] = p_vertices[i].y; - } - - if (p_colors) { - - for (int i = 0; i < p_points; i++) { - b[stride * i + color_ofs + 0] = p_colors[i].r; - b[stride * i + color_ofs + 1] = p_colors[i].g; - b[stride * i + color_ofs + 2] = p_colors[i].b; - b[stride * i + color_ofs + 3] = p_colors[i].a; - } - } - - if (p_uvs) { - - for (int i = 0; i < p_points; i++) { - b[stride * i + uv_ofs + 0] = p_uvs[i].x; - b[stride * i + uv_ofs + 1] = p_uvs[i].y; - } - } - - glBindBuffer(GL_ARRAY_BUFFER, data.polygon_buffer); -#ifndef GLES_OVER_GL - // Orphan the buffer to avoid CPU/GPU sync points caused by glBufferSubData - glBufferData(GL_ARRAY_BUFFER, data.polygon_buffer_size, NULL, GL_DYNAMIC_DRAW); -#endif - //TODO the below call may need to be replaced with: glBufferSubData(GL_ARRAY_BUFFER, 0, p_points * stride * 4 * sizeof(float), &b[0]); - glBufferSubData(GL_ARRAY_BUFFER, 0, p_points * stride * 4, &b[0]); - glBindVertexArray(data.polygon_buffer_quad_arrays[version]); - glDrawArrays(prim[p_points], 0, p_points); - glBindVertexArray(0); - glBindBuffer(GL_ARRAY_BUFFER, 0); - - storage->frame.canvas_draw_commands++; -} - -static const GLenum gl_primitive[] = { - GL_POINTS, - GL_LINES, - GL_LINE_STRIP, - GL_LINE_LOOP, - GL_TRIANGLES, - GL_TRIANGLE_STRIP, - GL_TRIANGLE_FAN -}; - -void RasterizerCanvasGLES3::_canvas_item_render_commands(Item *p_item, Item *current_clip, bool &reclip) { - - int cc = p_item->commands.size(); - Item::Command **commands = p_item->commands.ptrw(); - - for (int i = 0; i < cc; i++) { - - Item::Command *c = commands[i]; - - switch (c->type) { - case Item::Command::TYPE_LINE: { - - Item::CommandLine *line = static_cast<Item::CommandLine *>(c); - _set_texture_rect_mode(false); - - _bind_canvas_texture(RID(), RID()); - - glVertexAttrib4f(VS::ARRAY_COLOR, line->color.r, line->color.g, line->color.b, line->color.a); - - if (line->width <= 1) { - Vector2 verts[2] = { - Vector2(line->from.x, line->from.y), - Vector2(line->to.x, line->to.y) - }; - -#ifdef GLES_OVER_GL - if (line->antialiased) - glEnable(GL_LINE_SMOOTH); -#endif - //glLineWidth(line->width); - _draw_gui_primitive(2, verts, NULL, NULL); - -#ifdef GLES_OVER_GL - if (line->antialiased) - glDisable(GL_LINE_SMOOTH); -#endif - } else { - //thicker line - - Vector2 t = (line->from - line->to).normalized().tangent() * line->width * 0.5; - - Vector2 verts[4] = { - line->from - t, - line->from + t, - line->to + t, - line->to - t, - }; - - //glLineWidth(line->width); - _draw_gui_primitive(4, verts, NULL, NULL); -#ifdef GLES_OVER_GL - if (line->antialiased) { - glEnable(GL_LINE_SMOOTH); - for (int j = 0; j < 4; j++) { - Vector2 vertsl[2] = { - verts[j], - verts[(j + 1) % 4], - }; - _draw_gui_primitive(2, vertsl, NULL, NULL); - } - glDisable(GL_LINE_SMOOTH); - } -#endif - } - - } break; - case Item::Command::TYPE_POLYLINE: { - - Item::CommandPolyLine *pline = static_cast<Item::CommandPolyLine *>(c); - _set_texture_rect_mode(false); - - _bind_canvas_texture(RID(), RID()); - - if (pline->triangles.size()) { - - _draw_generic(GL_TRIANGLE_STRIP, pline->triangles.size(), pline->triangles.ptr(), NULL, pline->triangle_colors.ptr(), pline->triangle_colors.size() == 1); -#ifdef GLES_OVER_GL - glEnable(GL_LINE_SMOOTH); - if (pline->multiline) { - //needs to be different - } else { - _draw_generic(GL_LINE_LOOP, pline->lines.size(), pline->lines.ptr(), NULL, pline->line_colors.ptr(), pline->line_colors.size() == 1); - } - glDisable(GL_LINE_SMOOTH); -#endif - } else { - -#ifdef GLES_OVER_GL - if (pline->antialiased) - glEnable(GL_LINE_SMOOTH); -#endif - - if (pline->multiline) { - int todo = pline->lines.size() / 2; - int max_per_call = data.polygon_buffer_size / (sizeof(real_t) * 4); - int offset = 0; - - while (todo) { - int to_draw = MIN(max_per_call, todo); - _draw_generic(GL_LINES, to_draw * 2, &pline->lines.ptr()[offset], NULL, pline->line_colors.size() == 1 ? pline->line_colors.ptr() : &pline->line_colors.ptr()[offset], pline->line_colors.size() == 1); - todo -= to_draw; - offset += to_draw * 2; - } - - } else { - - _draw_generic(GL_LINE_STRIP, pline->lines.size(), pline->lines.ptr(), NULL, pline->line_colors.ptr(), pline->line_colors.size() == 1); - } - -#ifdef GLES_OVER_GL - if (pline->antialiased) - glDisable(GL_LINE_SMOOTH); -#endif - } - - } break; - case Item::Command::TYPE_RECT: { - - Item::CommandRect *rect = static_cast<Item::CommandRect *>(c); - - _set_texture_rect_mode(true); - - //set color - glVertexAttrib4f(VS::ARRAY_COLOR, rect->modulate.r, rect->modulate.g, rect->modulate.b, rect->modulate.a); - - RasterizerStorageGLES3::Texture *texture = _bind_canvas_texture(rect->texture, rect->normal_map); - - if (texture) { - - bool untile = false; - - if (rect->flags & CANVAS_RECT_TILE && !(texture->flags & VS::TEXTURE_FLAG_REPEAT)) { - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - untile = true; - } - - Size2 texpixel_size(1.0 / texture->width, 1.0 / texture->height); - Rect2 src_rect = (rect->flags & CANVAS_RECT_REGION) ? Rect2(rect->source.position * texpixel_size, rect->source.size * texpixel_size) : Rect2(0, 0, 1, 1); - Rect2 dst_rect = Rect2(rect->rect.position, rect->rect.size); - - if (dst_rect.size.width < 0) { - dst_rect.position.x += dst_rect.size.width; - dst_rect.size.width *= -1; - } - if (dst_rect.size.height < 0) { - dst_rect.position.y += dst_rect.size.height; - dst_rect.size.height *= -1; - } - - if (rect->flags & CANVAS_RECT_FLIP_H) { - src_rect.size.x *= -1; - } - - if (rect->flags & CANVAS_RECT_FLIP_V) { - src_rect.size.y *= -1; - } - - if (rect->flags & CANVAS_RECT_TRANSPOSE) { - dst_rect.size.x *= -1; // Encoding in the dst_rect.z uniform - } - - state.canvas_shader.set_uniform(CanvasShaderGLES3::COLOR_TEXPIXEL_SIZE, texpixel_size); - - state.canvas_shader.set_uniform(CanvasShaderGLES3::DST_RECT, Color(dst_rect.position.x, dst_rect.position.y, dst_rect.size.x, dst_rect.size.y)); - state.canvas_shader.set_uniform(CanvasShaderGLES3::SRC_RECT, Color(src_rect.position.x, src_rect.position.y, src_rect.size.x, src_rect.size.y)); - state.canvas_shader.set_uniform(CanvasShaderGLES3::CLIP_RECT_UV, rect->flags & CANVAS_RECT_CLIP_UV); - - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - - if (untile) { - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - } - - } else { - Rect2 dst_rect = Rect2(rect->rect.position, rect->rect.size); - - if (dst_rect.size.width < 0) { - dst_rect.position.x += dst_rect.size.width; - dst_rect.size.width *= -1; - } - if (dst_rect.size.height < 0) { - dst_rect.position.y += dst_rect.size.height; - dst_rect.size.height *= -1; - } - - state.canvas_shader.set_uniform(CanvasShaderGLES3::DST_RECT, Color(dst_rect.position.x, dst_rect.position.y, dst_rect.size.x, dst_rect.size.y)); - state.canvas_shader.set_uniform(CanvasShaderGLES3::SRC_RECT, Color(0, 0, 1, 1)); - state.canvas_shader.set_uniform(CanvasShaderGLES3::CLIP_RECT_UV, false); - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - } - - storage->frame.canvas_draw_commands++; - - } break; - - case Item::Command::TYPE_NINEPATCH: { - - Item::CommandNinePatch *np = static_cast<Item::CommandNinePatch *>(c); - - _set_texture_rect_mode(true, true); - - glVertexAttrib4f(VS::ARRAY_COLOR, np->color.r, np->color.g, np->color.b, np->color.a); - - RasterizerStorageGLES3::Texture *texture = _bind_canvas_texture(np->texture, np->normal_map); - - Size2 texpixel_size; - - if (!texture) { - - texpixel_size = Size2(1, 1); - - state.canvas_shader.set_uniform(CanvasShaderGLES3::SRC_RECT, Color(0, 0, 1, 1)); - - } else { - - if (np->source != Rect2()) { - texpixel_size = Size2(1.0 / np->source.size.width, 1.0 / np->source.size.height); - state.canvas_shader.set_uniform(CanvasShaderGLES3::SRC_RECT, Color(np->source.position.x / texture->width, np->source.position.y / texture->height, np->source.size.x / texture->width, np->source.size.y / texture->height)); - } else { - texpixel_size = Size2(1.0 / texture->width, 1.0 / texture->height); - state.canvas_shader.set_uniform(CanvasShaderGLES3::SRC_RECT, Color(0, 0, 1, 1)); - } - } - - state.canvas_shader.set_uniform(CanvasShaderGLES3::COLOR_TEXPIXEL_SIZE, texpixel_size); - state.canvas_shader.set_uniform(CanvasShaderGLES3::CLIP_RECT_UV, false); - state.canvas_shader.set_uniform(CanvasShaderGLES3::NP_REPEAT_H, int(np->axis_x)); - state.canvas_shader.set_uniform(CanvasShaderGLES3::NP_REPEAT_V, int(np->axis_y)); - state.canvas_shader.set_uniform(CanvasShaderGLES3::NP_DRAW_CENTER, np->draw_center); - state.canvas_shader.set_uniform(CanvasShaderGLES3::NP_MARGINS, Color(np->margin[MARGIN_LEFT], np->margin[MARGIN_TOP], np->margin[MARGIN_RIGHT], np->margin[MARGIN_BOTTOM])); - state.canvas_shader.set_uniform(CanvasShaderGLES3::DST_RECT, Color(np->rect.position.x, np->rect.position.y, np->rect.size.x, np->rect.size.y)); - - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - - storage->frame.canvas_draw_commands++; - } break; - - case Item::Command::TYPE_PRIMITIVE: { - - Item::CommandPrimitive *primitive = static_cast<Item::CommandPrimitive *>(c); - _set_texture_rect_mode(false); - - ERR_CONTINUE(primitive->points.size() < 1); - - RasterizerStorageGLES3::Texture *texture = _bind_canvas_texture(primitive->texture, primitive->normal_map); - - if (texture) { - Size2 texpixel_size(1.0 / texture->width, 1.0 / texture->height); - state.canvas_shader.set_uniform(CanvasShaderGLES3::COLOR_TEXPIXEL_SIZE, texpixel_size); - } - if (primitive->colors.size() == 1 && primitive->points.size() > 1) { - - Color col = primitive->colors[0]; - glVertexAttrib4f(VS::ARRAY_COLOR, col.r, col.g, col.b, col.a); - - } else if (primitive->colors.empty()) { - glVertexAttrib4f(VS::ARRAY_COLOR, 1, 1, 1, 1); - } - - _draw_gui_primitive(primitive->points.size(), primitive->points.ptr(), primitive->colors.ptr(), primitive->uvs.ptr()); - - } break; - case Item::Command::TYPE_POLYGON: { - - Item::CommandPolygon *polygon = static_cast<Item::CommandPolygon *>(c); - _set_texture_rect_mode(false); - - RasterizerStorageGLES3::Texture *texture = _bind_canvas_texture(polygon->texture, polygon->normal_map); - - if (texture) { - Size2 texpixel_size(1.0 / texture->width, 1.0 / texture->height); - state.canvas_shader.set_uniform(CanvasShaderGLES3::COLOR_TEXPIXEL_SIZE, texpixel_size); - } - - _draw_polygon(polygon->indices.ptr(), polygon->count, polygon->points.size(), polygon->points.ptr(), polygon->uvs.ptr(), polygon->colors.ptr(), polygon->colors.size() == 1, polygon->bones.ptr(), polygon->weights.ptr()); -#ifdef GLES_OVER_GL - if (polygon->antialiased) { - glEnable(GL_LINE_SMOOTH); - if (polygon->antialiasing_use_indices) { - _draw_generic_indices(GL_LINE_STRIP, polygon->indices.ptr(), polygon->count, polygon->points.size(), polygon->points.ptr(), polygon->uvs.ptr(), polygon->colors.ptr(), polygon->colors.size() == 1); - } else { - _draw_generic(GL_LINE_LOOP, polygon->points.size(), polygon->points.ptr(), polygon->uvs.ptr(), polygon->colors.ptr(), polygon->colors.size() == 1); - } - glDisable(GL_LINE_SMOOTH); - } -#endif - - } break; - case Item::Command::TYPE_MESH: { - - Item::CommandMesh *mesh = static_cast<Item::CommandMesh *>(c); - _set_texture_rect_mode(false); - - RasterizerStorageGLES3::Texture *texture = _bind_canvas_texture(mesh->texture, mesh->normal_map); - - if (texture) { - Size2 texpixel_size(1.0 / texture->width, 1.0 / texture->height); - state.canvas_shader.set_uniform(CanvasShaderGLES3::COLOR_TEXPIXEL_SIZE, texpixel_size); - } - - state.canvas_shader.set_uniform(CanvasShaderGLES3::MODELVIEW_MATRIX, state.final_transform * mesh->transform); - - RasterizerStorageGLES3::Mesh *mesh_data = storage->mesh_owner.getornull(mesh->mesh); - if (mesh_data) { - - for (int j = 0; j < mesh_data->surfaces.size(); j++) { - RasterizerStorageGLES3::Surface *s = mesh_data->surfaces[j]; - // materials are ignored in 2D meshes, could be added but many things (ie, lighting mode, reading from screen, etc) would break as they are not meant be set up at this point of drawing - glBindVertexArray(s->array_id); - - glVertexAttrib4f(VS::ARRAY_COLOR, mesh->modulate.r, mesh->modulate.g, mesh->modulate.b, mesh->modulate.a); - - if (s->index_array_len) { - glDrawElements(gl_primitive[s->primitive], s->index_array_len, (s->array_len >= (1 << 16)) ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT, 0); - } else { - glDrawArrays(gl_primitive[s->primitive], 0, s->array_len); - } - - glBindVertexArray(0); - } - } - state.canvas_shader.set_uniform(CanvasShaderGLES3::MODELVIEW_MATRIX, state.final_transform); - - } break; - case Item::Command::TYPE_MULTIMESH: { - - Item::CommandMultiMesh *mmesh = static_cast<Item::CommandMultiMesh *>(c); - - RasterizerStorageGLES3::MultiMesh *multi_mesh = storage->multimesh_owner.getornull(mmesh->multimesh); - - if (!multi_mesh) - break; - - RasterizerStorageGLES3::Mesh *mesh_data = storage->mesh_owner.getornull(multi_mesh->mesh); - - if (!mesh_data) - break; - - RasterizerStorageGLES3::Texture *texture = _bind_canvas_texture(mmesh->texture, mmesh->normal_map); - - state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_INSTANCE_CUSTOM, multi_mesh->custom_data_format != VS::MULTIMESH_CUSTOM_DATA_NONE); - state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_INSTANCING, true); - //reset shader and force rebind - state.using_texture_rect = true; - _set_texture_rect_mode(false); - - if (texture) { - Size2 texpixel_size(1.0 / texture->width, 1.0 / texture->height); - state.canvas_shader.set_uniform(CanvasShaderGLES3::COLOR_TEXPIXEL_SIZE, texpixel_size); - } - - int amount = MIN(multi_mesh->size, multi_mesh->visible_instances); - - if (amount == -1) { - amount = multi_mesh->size; - } - - for (int j = 0; j < mesh_data->surfaces.size(); j++) { - RasterizerStorageGLES3::Surface *s = mesh_data->surfaces[j]; - // materials are ignored in 2D meshes, could be added but many things (ie, lighting mode, reading from screen, etc) would break as they are not meant be set up at this point of drawing - glBindVertexArray(s->instancing_array_id); - - glBindBuffer(GL_ARRAY_BUFFER, multi_mesh->buffer); //modify the buffer - - int stride = (multi_mesh->xform_floats + multi_mesh->color_floats + multi_mesh->custom_data_floats) * 4; - glEnableVertexAttribArray(8); - glVertexAttribPointer(8, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(0)); - glVertexAttribDivisor(8, 1); - glEnableVertexAttribArray(9); - glVertexAttribPointer(9, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(4 * 4)); - glVertexAttribDivisor(9, 1); - - int color_ofs; - - if (multi_mesh->transform_format == VS::MULTIMESH_TRANSFORM_3D) { - glEnableVertexAttribArray(10); - glVertexAttribPointer(10, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(8 * 4)); - glVertexAttribDivisor(10, 1); - color_ofs = 12 * 4; - } else { - glDisableVertexAttribArray(10); - glVertexAttrib4f(10, 0, 0, 1, 0); - color_ofs = 8 * 4; - } - - int custom_data_ofs = color_ofs; - - switch (multi_mesh->color_format) { - - case VS::MULTIMESH_COLOR_MAX: - case VS::MULTIMESH_COLOR_NONE: { - glDisableVertexAttribArray(11); - glVertexAttrib4f(11, 1, 1, 1, 1); - } break; - case VS::MULTIMESH_COLOR_8BIT: { - glEnableVertexAttribArray(11); - glVertexAttribPointer(11, 4, GL_UNSIGNED_BYTE, GL_TRUE, stride, CAST_INT_TO_UCHAR_PTR(color_ofs)); - glVertexAttribDivisor(11, 1); - custom_data_ofs += 4; - - } break; - case VS::MULTIMESH_COLOR_FLOAT: { - glEnableVertexAttribArray(11); - glVertexAttribPointer(11, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(color_ofs)); - glVertexAttribDivisor(11, 1); - custom_data_ofs += 4 * 4; - } break; - } - - switch (multi_mesh->custom_data_format) { - - case VS::MULTIMESH_CUSTOM_DATA_MAX: - case VS::MULTIMESH_CUSTOM_DATA_NONE: { - glDisableVertexAttribArray(12); - glVertexAttrib4f(12, 1, 1, 1, 1); - } break; - case VS::MULTIMESH_CUSTOM_DATA_8BIT: { - glEnableVertexAttribArray(12); - glVertexAttribPointer(12, 4, GL_UNSIGNED_BYTE, GL_TRUE, stride, CAST_INT_TO_UCHAR_PTR(custom_data_ofs)); - glVertexAttribDivisor(12, 1); - - } break; - case VS::MULTIMESH_CUSTOM_DATA_FLOAT: { - glEnableVertexAttribArray(12); - glVertexAttribPointer(12, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(custom_data_ofs)); - glVertexAttribDivisor(12, 1); - } break; - } - - if (s->index_array_len) { - glDrawElementsInstanced(gl_primitive[s->primitive], s->index_array_len, (s->array_len >= (1 << 16)) ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT, 0, amount); - } else { - glDrawArraysInstanced(gl_primitive[s->primitive], 0, s->array_len, amount); - } - - glBindVertexArray(0); - } - - state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_INSTANCE_CUSTOM, false); - state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_INSTANCING, false); - state.using_texture_rect = true; - _set_texture_rect_mode(false); - - } break; - case Item::Command::TYPE_PARTICLES: { - - Item::CommandParticles *particles_cmd = static_cast<Item::CommandParticles *>(c); - - RasterizerStorageGLES3::Particles *particles = storage->particles_owner.getornull(particles_cmd->particles); - if (!particles) - break; - - if (particles->inactive && !particles->emitting) - break; - - glVertexAttrib4f(VS::ARRAY_COLOR, 1, 1, 1, 1); //not used, so keep white - - VisualServerRaster::redraw_request(); - - storage->particles_request_process(particles_cmd->particles); - //enable instancing - - state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_INSTANCE_CUSTOM, true); - state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_PARTICLES, true); - state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_INSTANCING, true); - //reset shader and force rebind - state.using_texture_rect = true; - _set_texture_rect_mode(false); - - RasterizerStorageGLES3::Texture *texture = _bind_canvas_texture(particles_cmd->texture, particles_cmd->normal_map); - - if (texture) { - Size2 texpixel_size(1.0 / texture->width, 1.0 / texture->height); - state.canvas_shader.set_uniform(CanvasShaderGLES3::COLOR_TEXPIXEL_SIZE, texpixel_size); - } else { - state.canvas_shader.set_uniform(CanvasShaderGLES3::COLOR_TEXPIXEL_SIZE, Vector2(1.0, 1.0)); - } - - if (!particles->use_local_coords) { - - Transform2D inv_xf; - inv_xf.set_axis(0, Vector2(particles->emission_transform.basis.get_axis(0).x, particles->emission_transform.basis.get_axis(0).y)); - inv_xf.set_axis(1, Vector2(particles->emission_transform.basis.get_axis(1).x, particles->emission_transform.basis.get_axis(1).y)); - inv_xf.set_origin(Vector2(particles->emission_transform.get_origin().x, particles->emission_transform.get_origin().y)); - inv_xf.affine_invert(); - - state.canvas_shader.set_uniform(CanvasShaderGLES3::MODELVIEW_MATRIX, state.final_transform * inv_xf); - } - - glBindVertexArray(data.particle_quad_array); //use particle quad array - glBindBuffer(GL_ARRAY_BUFFER, particles->particle_buffers[0]); //bind particle buffer - - int stride = sizeof(float) * 4 * 6; - - int amount = particles->amount; - - if (particles->draw_order != VS::PARTICLES_DRAW_ORDER_LIFETIME) { - - glEnableVertexAttribArray(8); //xform x - glVertexAttribPointer(8, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(sizeof(float) * 4 * 3)); - glVertexAttribDivisor(8, 1); - glEnableVertexAttribArray(9); //xform y - glVertexAttribPointer(9, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(sizeof(float) * 4 * 4)); - glVertexAttribDivisor(9, 1); - glEnableVertexAttribArray(10); //xform z - glVertexAttribPointer(10, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(sizeof(float) * 4 * 5)); - glVertexAttribDivisor(10, 1); - glEnableVertexAttribArray(11); //color - glVertexAttribPointer(11, 4, GL_FLOAT, GL_FALSE, stride, NULL); - glVertexAttribDivisor(11, 1); - glEnableVertexAttribArray(12); //custom - glVertexAttribPointer(12, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(sizeof(float) * 4 * 2)); - glVertexAttribDivisor(12, 1); - - glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, amount); - } else { - //split - int split = int(Math::ceil(particles->phase * particles->amount)); - - if (amount - split > 0) { - glEnableVertexAttribArray(8); //xform x - glVertexAttribPointer(8, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(stride * split + sizeof(float) * 4 * 3)); - glVertexAttribDivisor(8, 1); - glEnableVertexAttribArray(9); //xform y - glVertexAttribPointer(9, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(stride * split + sizeof(float) * 4 * 4)); - glVertexAttribDivisor(9, 1); - glEnableVertexAttribArray(10); //xform z - glVertexAttribPointer(10, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(stride * split + sizeof(float) * 4 * 5)); - glVertexAttribDivisor(10, 1); - glEnableVertexAttribArray(11); //color - glVertexAttribPointer(11, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(stride * split + 0)); - glVertexAttribDivisor(11, 1); - glEnableVertexAttribArray(12); //custom - glVertexAttribPointer(12, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(stride * split + sizeof(float) * 4 * 2)); - glVertexAttribDivisor(12, 1); - - glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, amount - split); - } - - if (split > 0) { - glEnableVertexAttribArray(8); //xform x - glVertexAttribPointer(8, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(sizeof(float) * 4 * 3)); - glVertexAttribDivisor(8, 1); - glEnableVertexAttribArray(9); //xform y - glVertexAttribPointer(9, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(sizeof(float) * 4 * 4)); - glVertexAttribDivisor(9, 1); - glEnableVertexAttribArray(10); //xform z - glVertexAttribPointer(10, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(sizeof(float) * 4 * 5)); - glVertexAttribDivisor(10, 1); - glEnableVertexAttribArray(11); //color - glVertexAttribPointer(11, 4, GL_FLOAT, GL_FALSE, stride, NULL); - glVertexAttribDivisor(11, 1); - glEnableVertexAttribArray(12); //custom - glVertexAttribPointer(12, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(sizeof(float) * 4 * 2)); - glVertexAttribDivisor(12, 1); - - glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, split); - } - } - - glBindVertexArray(0); - - state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_INSTANCE_CUSTOM, false); - state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_PARTICLES, false); - state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_INSTANCING, false); - state.using_texture_rect = true; - _set_texture_rect_mode(false); - - } break; - case Item::Command::TYPE_CIRCLE: { - - _set_texture_rect_mode(false); - - Item::CommandCircle *circle = static_cast<Item::CommandCircle *>(c); - static const int numpoints = 32; - Vector2 points[numpoints + 1]; - points[numpoints] = circle->pos; - int indices[numpoints * 3]; - - for (int j = 0; j < numpoints; j++) { - - points[j] = circle->pos + Vector2(Math::sin(j * Math_PI * 2.0 / numpoints), Math::cos(j * Math_PI * 2.0 / numpoints)) * circle->radius; - indices[j * 3 + 0] = j; - indices[j * 3 + 1] = (j + 1) % numpoints; - indices[j * 3 + 2] = numpoints; - } - - _bind_canvas_texture(RID(), RID()); - _draw_polygon(indices, numpoints * 3, numpoints + 1, points, NULL, &circle->color, true, NULL, NULL); - - //_draw_polygon(numpoints*3,indices,points,NULL,&circle->color,RID(),true); - //canvas_draw_circle(circle->indices.size(),circle->indices.ptr(),circle->points.ptr(),circle->uvs.ptr(),circle->colors.ptr(),circle->texture,circle->colors.size()==1); - } break; - case Item::Command::TYPE_TRANSFORM: { - - Item::CommandTransform *transform = static_cast<Item::CommandTransform *>(c); - state.extra_matrix = transform->xform; - state.canvas_shader.set_uniform(CanvasShaderGLES3::EXTRA_MATRIX, state.extra_matrix); - - } break; - case Item::Command::TYPE_CLIP_IGNORE: { - - Item::CommandClipIgnore *ci = static_cast<Item::CommandClipIgnore *>(c); - if (current_clip) { - - if (ci->ignore != reclip) { - if (ci->ignore) { - - glDisable(GL_SCISSOR_TEST); - reclip = true; - } else { - - glEnable(GL_SCISSOR_TEST); - //glScissor(viewport.x+current_clip->final_clip_rect.pos.x,viewport.y+ (viewport.height-(current_clip->final_clip_rect.pos.y+current_clip->final_clip_rect.size.height)), - //current_clip->final_clip_rect.size.width,current_clip->final_clip_rect.size.height); - int y = storage->frame.current_rt->height - (current_clip->final_clip_rect.position.y + current_clip->final_clip_rect.size.y); - if (storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_VFLIP]) - y = current_clip->final_clip_rect.position.y; - - glScissor(current_clip->final_clip_rect.position.x, y, current_clip->final_clip_rect.size.x, current_clip->final_clip_rect.size.y); - - reclip = false; - } - } - } - - } break; - } - } -} - -void RasterizerCanvasGLES3::_copy_texscreen(const Rect2 &p_rect) { - - ERR_FAIL_COND_MSG(storage->frame.current_rt->effects.mip_maps[0].sizes.size() == 0, "Can't use screen texture copying in a render target configured without copy buffers."); - - glDisable(GL_BLEND); - - state.canvas_texscreen_used = true; - //blur diffuse into effect mipmaps using separatable convolution - //storage->shaders.copy.set_conditional(CopyShaderGLES3::GAUSSIAN_HORIZONTAL,true); - - Vector2 wh(storage->frame.current_rt->width, storage->frame.current_rt->height); - - Color blur_section(p_rect.position.x / wh.x, p_rect.position.y / wh.y, p_rect.size.x / wh.x, p_rect.size.y / wh.y); - - if (p_rect != Rect2()) { - - scene_render->state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::USE_BLUR_SECTION, true); - storage->shaders.copy.set_conditional(CopyShaderGLES3::USE_COPY_SECTION, true); - } - - glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->effects.mip_maps[0].sizes[0].fbo); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->color); - - storage->shaders.copy.bind(); - storage->shaders.copy.set_uniform(CopyShaderGLES3::COPY_SECTION, blur_section); - - scene_render->_copy_screen(); - - for (int i = 0; i < storage->frame.current_rt->effects.mip_maps[1].sizes.size(); i++) { - - int vp_w = storage->frame.current_rt->effects.mip_maps[1].sizes[i].width; - int vp_h = storage->frame.current_rt->effects.mip_maps[1].sizes[i].height; - glViewport(0, 0, vp_w, vp_h); - //horizontal pass - scene_render->state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::GAUSSIAN_HORIZONTAL, true); - scene_render->state.effect_blur_shader.bind(); - scene_render->state.effect_blur_shader.set_uniform(EffectBlurShaderGLES3::PIXEL_SIZE, Vector2(1.0 / vp_w, 1.0 / vp_h)); - scene_render->state.effect_blur_shader.set_uniform(EffectBlurShaderGLES3::LOD, float(i)); - scene_render->state.effect_blur_shader.set_uniform(EffectBlurShaderGLES3::BLUR_SECTION, blur_section); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->effects.mip_maps[0].color); //previous level, since mipmaps[0] starts one level bigger - glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->effects.mip_maps[1].sizes[i].fbo); - - scene_render->_copy_screen(); - - scene_render->state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::GAUSSIAN_HORIZONTAL, false); - - //vertical pass - scene_render->state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::GAUSSIAN_VERTICAL, true); - scene_render->state.effect_blur_shader.bind(); - scene_render->state.effect_blur_shader.set_uniform(EffectBlurShaderGLES3::PIXEL_SIZE, Vector2(1.0 / vp_w, 1.0 / vp_h)); - scene_render->state.effect_blur_shader.set_uniform(EffectBlurShaderGLES3::LOD, float(i)); - scene_render->state.effect_blur_shader.set_uniform(EffectBlurShaderGLES3::BLUR_SECTION, blur_section); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->effects.mip_maps[1].color); - glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->effects.mip_maps[0].sizes[i + 1].fbo); //next level, since mipmaps[0] starts one level bigger - - scene_render->_copy_screen(); - - scene_render->state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::GAUSSIAN_VERTICAL, false); - } - - scene_render->state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::USE_BLUR_SECTION, false); - storage->shaders.copy.set_conditional(CopyShaderGLES3::USE_COPY_SECTION, false); - - glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->fbo); //back to front - glViewport(0, 0, storage->frame.current_rt->width, storage->frame.current_rt->height); - - // back to canvas, force rebind - state.using_texture_rect = true; - _set_texture_rect_mode(false); - - _bind_canvas_texture(state.current_tex, state.current_normal, true); - - glEnable(GL_BLEND); -} - -void RasterizerCanvasGLES3::canvas_render_items(Item *p_item_list, int p_z, const Color &p_modulate, Light *p_light, const Transform2D &p_transform) { - - Item *current_clip = NULL; - RasterizerStorageGLES3::Shader *shader_cache = NULL; - - bool rebind_shader = true; - - glBindBuffer(GL_UNIFORM_BUFFER, state.canvas_item_ubo); - glBufferData(GL_UNIFORM_BUFFER, sizeof(CanvasItemUBO), &state.canvas_item_ubo_data, GL_DYNAMIC_DRAW); - glBindBuffer(GL_UNIFORM_BUFFER, 0); - - state.current_tex = RID(); - state.current_tex_ptr = NULL; - state.current_normal = RID(); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, storage->resources.white_tex); - - int last_blend_mode = -1; - - RID canvas_last_material; - - bool prev_distance_field = false; - bool prev_use_skeleton = false; - - while (p_item_list) { - - Item *ci = p_item_list; - - if (prev_distance_field != ci->distance_field) { - - state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_DISTANCE_FIELD, ci->distance_field); - prev_distance_field = ci->distance_field; - rebind_shader = true; - } - - if (current_clip != ci->final_clip_owner) { - - current_clip = ci->final_clip_owner; - - //setup clip - if (current_clip) { - - glEnable(GL_SCISSOR_TEST); - int y = storage->frame.current_rt->height - (current_clip->final_clip_rect.position.y + current_clip->final_clip_rect.size.y); - if (storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_VFLIP]) - y = current_clip->final_clip_rect.position.y; - - glScissor(current_clip->final_clip_rect.position.x, y, current_clip->final_clip_rect.size.x, current_clip->final_clip_rect.size.y); - - } else { - - glDisable(GL_SCISSOR_TEST); - } - } - - if (ci->copy_back_buffer) { - - if (ci->copy_back_buffer->full) { - - _copy_texscreen(Rect2()); - } else { - _copy_texscreen(ci->copy_back_buffer->rect); - } - } - - RasterizerStorageGLES3::Skeleton *skeleton = NULL; - - { - //skeleton handling - if (ci->skeleton.is_valid() && storage->skeleton_owner.owns(ci->skeleton)) { - skeleton = storage->skeleton_owner.get(ci->skeleton); - if (!skeleton->use_2d) { - skeleton = NULL; - } else { - state.skeleton_transform = p_transform * skeleton->base_transform_2d; - state.skeleton_transform_inverse = state.skeleton_transform.affine_inverse(); - } - } - - bool use_skeleton = skeleton != NULL; - if (prev_use_skeleton != use_skeleton) { - rebind_shader = true; - state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_SKELETON, use_skeleton); - prev_use_skeleton = use_skeleton; - } - - if (skeleton) { - glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 4); - glBindTexture(GL_TEXTURE_2D, skeleton->texture); - state.using_skeleton = true; - } else { - state.using_skeleton = false; - } - } - - //begin rect - Item *material_owner = ci->material_owner ? ci->material_owner : ci; - - RID material = material_owner->material; - - if (material != canvas_last_material || rebind_shader) { - - RasterizerStorageGLES3::Material *material_ptr = storage->material_owner.getornull(material); - RasterizerStorageGLES3::Shader *shader_ptr = NULL; - - if (material_ptr) { - - shader_ptr = material_ptr->shader; - - if (shader_ptr && shader_ptr->mode != VS::SHADER_CANVAS_ITEM) { - shader_ptr = NULL; //do not use non canvasitem shader - } - } - - if (shader_ptr) { - - if (shader_ptr->canvas_item.uses_screen_texture && !state.canvas_texscreen_used) { - //copy if not copied before - _copy_texscreen(Rect2()); - - // blend mode will have been enabled so make sure we disable it again later on - last_blend_mode = last_blend_mode != RasterizerStorageGLES3::Shader::CanvasItem::BLEND_MODE_DISABLED ? last_blend_mode : -1; - } - - if (shader_ptr != shader_cache || rebind_shader) { - - if (shader_ptr->canvas_item.uses_time) { - VisualServerRaster::redraw_request(); - } - - state.canvas_shader.set_custom_shader(shader_ptr->custom_code_id); - state.canvas_shader.bind(); - } - - if (material_ptr->ubo_id) { - glBindBufferBase(GL_UNIFORM_BUFFER, 2, material_ptr->ubo_id); - } - - int tc = material_ptr->textures.size(); - RID *textures = material_ptr->textures.ptrw(); - ShaderLanguage::ShaderNode::Uniform::Hint *texture_hints = shader_ptr->texture_hints.ptrw(); - - for (int i = 0; i < tc; i++) { - - glActiveTexture(GL_TEXTURE2 + i); - - RasterizerStorageGLES3::Texture *t = storage->texture_owner.getornull(textures[i]); - if (!t) { - - switch (texture_hints[i]) { - case ShaderLanguage::ShaderNode::Uniform::HINT_BLACK_ALBEDO: - case ShaderLanguage::ShaderNode::Uniform::HINT_BLACK: { - glBindTexture(GL_TEXTURE_2D, storage->resources.black_tex); - } break; - case ShaderLanguage::ShaderNode::Uniform::HINT_ANISO: { - glBindTexture(GL_TEXTURE_2D, storage->resources.aniso_tex); - } break; - case ShaderLanguage::ShaderNode::Uniform::HINT_NORMAL: { - glBindTexture(GL_TEXTURE_2D, storage->resources.normal_tex); - } break; - default: { - glBindTexture(GL_TEXTURE_2D, storage->resources.white_tex); - } break; - } - - //check hints - - continue; - } - - if (t->redraw_if_visible) { //check before proxy, because this is usually used with proxies - VisualServerRaster::redraw_request(); - } - - t = t->get_ptr(); - - if (storage->config.srgb_decode_supported && t->using_srgb) { - //no srgb in 2D - glTexParameteri(t->target, _TEXTURE_SRGB_DECODE_EXT, _SKIP_DECODE_EXT); - t->using_srgb = false; - } - - glBindTexture(t->target, t->tex_id); - } - - } else { - state.canvas_shader.set_custom_shader(0); - state.canvas_shader.bind(); - } - - shader_cache = shader_ptr; - - canvas_last_material = material; - rebind_shader = false; - } - - int blend_mode = shader_cache ? shader_cache->canvas_item.blend_mode : RasterizerStorageGLES3::Shader::CanvasItem::BLEND_MODE_MIX; - if (blend_mode == RasterizerStorageGLES3::Shader::CanvasItem::BLEND_MODE_DISABLED && (!storage->frame.current_rt || !storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT])) { - blend_mode = RasterizerStorageGLES3::Shader::CanvasItem::BLEND_MODE_MIX; - } - bool unshaded = shader_cache && (shader_cache->canvas_item.light_mode == RasterizerStorageGLES3::Shader::CanvasItem::LIGHT_MODE_UNSHADED || (blend_mode != RasterizerStorageGLES3::Shader::CanvasItem::BLEND_MODE_MIX && blend_mode != RasterizerStorageGLES3::Shader::CanvasItem::BLEND_MODE_PMALPHA)); - bool reclip = false; - - if (last_blend_mode != blend_mode) { - if (last_blend_mode == RasterizerStorageGLES3::Shader::CanvasItem::BLEND_MODE_DISABLED) { - // re-enable it - glEnable(GL_BLEND); - } else if (blend_mode == RasterizerStorageGLES3::Shader::CanvasItem::BLEND_MODE_DISABLED) { - // disable it - glDisable(GL_BLEND); - } - - switch (blend_mode) { - - case RasterizerStorageGLES3::Shader::CanvasItem::BLEND_MODE_DISABLED: { - - // nothing to do here - - } break; - case RasterizerStorageGLES3::Shader::CanvasItem::BLEND_MODE_MIX: { - - glBlendEquation(GL_FUNC_ADD); - if (storage->frame.current_rt && storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]) { - glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - } else { - glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE); - } - - } break; - case RasterizerStorageGLES3::Shader::CanvasItem::BLEND_MODE_ADD: { - - glBlendEquation(GL_FUNC_ADD); - if (storage->frame.current_rt && storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]) { - glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE, GL_SRC_ALPHA, GL_ONE); - } else { - glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE, GL_ZERO, GL_ONE); - } - - } break; - case RasterizerStorageGLES3::Shader::CanvasItem::BLEND_MODE_SUB: { - - glBlendEquation(GL_FUNC_REVERSE_SUBTRACT); - if (storage->frame.current_rt && storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]) { - glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE, GL_SRC_ALPHA, GL_ONE); - } else { - glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE, GL_ZERO, GL_ONE); - } - } break; - case RasterizerStorageGLES3::Shader::CanvasItem::BLEND_MODE_MUL: { - glBlendEquation(GL_FUNC_ADD); - if (storage->frame.current_rt && storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]) { - glBlendFuncSeparate(GL_DST_COLOR, GL_ZERO, GL_DST_ALPHA, GL_ZERO); - } else { - glBlendFuncSeparate(GL_DST_COLOR, GL_ZERO, GL_ZERO, GL_ONE); - } - - } break; - case RasterizerStorageGLES3::Shader::CanvasItem::BLEND_MODE_PMALPHA: { - glBlendEquation(GL_FUNC_ADD); - if (storage->frame.current_rt && storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]) { - glBlendFuncSeparate(GL_ONE, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - } else { - glBlendFuncSeparate(GL_ONE, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE); - } - - } break; - } - - last_blend_mode = blend_mode; - } - - state.canvas_item_modulate = unshaded ? ci->final_modulate : Color(ci->final_modulate.r * p_modulate.r, ci->final_modulate.g * p_modulate.g, ci->final_modulate.b * p_modulate.b, ci->final_modulate.a * p_modulate.a); - - state.final_transform = ci->final_transform; - state.extra_matrix = Transform2D(); - - if (state.using_skeleton) { - state.canvas_shader.set_uniform(CanvasShaderGLES3::SKELETON_TRANSFORM, state.skeleton_transform); - state.canvas_shader.set_uniform(CanvasShaderGLES3::SKELETON_TRANSFORM_INVERSE, state.skeleton_transform_inverse); - } - - state.canvas_shader.set_uniform(CanvasShaderGLES3::FINAL_MODULATE, state.canvas_item_modulate); - state.canvas_shader.set_uniform(CanvasShaderGLES3::MODELVIEW_MATRIX, state.final_transform); - state.canvas_shader.set_uniform(CanvasShaderGLES3::EXTRA_MATRIX, state.extra_matrix); - if (storage->frame.current_rt) { - state.canvas_shader.set_uniform(CanvasShaderGLES3::SCREEN_PIXEL_SIZE, Vector2(1.0 / storage->frame.current_rt->width, 1.0 / storage->frame.current_rt->height)); - } else { - state.canvas_shader.set_uniform(CanvasShaderGLES3::SCREEN_PIXEL_SIZE, Vector2(1.0, 1.0)); - } - if (unshaded || (state.canvas_item_modulate.a > 0.001 && (!shader_cache || shader_cache->canvas_item.light_mode != RasterizerStorageGLES3::Shader::CanvasItem::LIGHT_MODE_LIGHT_ONLY) && !ci->light_masked)) - _canvas_item_render_commands(ci, current_clip, reclip); - - if ((blend_mode == RasterizerStorageGLES3::Shader::CanvasItem::BLEND_MODE_MIX || blend_mode == RasterizerStorageGLES3::Shader::CanvasItem::BLEND_MODE_PMALPHA) && p_light && !unshaded) { - - Light *light = p_light; - bool light_used = false; - VS::CanvasLightMode mode = VS::CANVAS_LIGHT_MODE_ADD; - state.canvas_item_modulate = ci->final_modulate; // remove the canvas modulate - - while (light) { - - if (ci->light_mask & light->item_mask && p_z >= light->z_min && p_z <= light->z_max && ci->global_rect_cache.intersects_transformed(light->xform_cache, light->rect_cache)) { - - //intersects this light - - if (!light_used || mode != light->mode) { - - mode = light->mode; - - switch (mode) { - - case VS::CANVAS_LIGHT_MODE_ADD: { - glBlendEquation(GL_FUNC_ADD); - glBlendFunc(GL_SRC_ALPHA, GL_ONE); - - } break; - case VS::CANVAS_LIGHT_MODE_SUB: { - glBlendEquation(GL_FUNC_REVERSE_SUBTRACT); - glBlendFunc(GL_SRC_ALPHA, GL_ONE); - } break; - case VS::CANVAS_LIGHT_MODE_MIX: - case VS::CANVAS_LIGHT_MODE_MASK: { - glBlendEquation(GL_FUNC_ADD); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - } break; - } - } - - if (!light_used) { - - state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_LIGHTING, true); - light_used = true; - } - - bool has_shadow = light->shadow_buffer.is_valid() && ci->light_mask & light->item_shadow_mask; - - state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_SHADOWS, has_shadow); - if (has_shadow) { - state.canvas_shader.set_conditional(CanvasShaderGLES3::SHADOW_USE_GRADIENT, light->shadow_gradient_length > 0); - state.canvas_shader.set_conditional(CanvasShaderGLES3::SHADOW_FILTER_NEAREST, light->shadow_filter == VS::CANVAS_LIGHT_FILTER_NONE); - state.canvas_shader.set_conditional(CanvasShaderGLES3::SHADOW_FILTER_PCF3, light->shadow_filter == VS::CANVAS_LIGHT_FILTER_PCF3); - state.canvas_shader.set_conditional(CanvasShaderGLES3::SHADOW_FILTER_PCF5, light->shadow_filter == VS::CANVAS_LIGHT_FILTER_PCF5); - state.canvas_shader.set_conditional(CanvasShaderGLES3::SHADOW_FILTER_PCF7, light->shadow_filter == VS::CANVAS_LIGHT_FILTER_PCF7); - state.canvas_shader.set_conditional(CanvasShaderGLES3::SHADOW_FILTER_PCF9, light->shadow_filter == VS::CANVAS_LIGHT_FILTER_PCF9); - state.canvas_shader.set_conditional(CanvasShaderGLES3::SHADOW_FILTER_PCF13, light->shadow_filter == VS::CANVAS_LIGHT_FILTER_PCF13); - } - - bool light_rebind = state.canvas_shader.bind(); - - if (light_rebind) { - state.canvas_shader.set_uniform(CanvasShaderGLES3::FINAL_MODULATE, state.canvas_item_modulate); - state.canvas_shader.set_uniform(CanvasShaderGLES3::MODELVIEW_MATRIX, state.final_transform); - state.canvas_shader.set_uniform(CanvasShaderGLES3::EXTRA_MATRIX, Transform2D()); - if (storage->frame.current_rt) { - state.canvas_shader.set_uniform(CanvasShaderGLES3::SCREEN_PIXEL_SIZE, Vector2(1.0 / storage->frame.current_rt->width, 1.0 / storage->frame.current_rt->height)); - } else { - state.canvas_shader.set_uniform(CanvasShaderGLES3::SCREEN_PIXEL_SIZE, Vector2(1.0, 1.0)); - } - if (state.using_skeleton) { - state.canvas_shader.set_uniform(CanvasShaderGLES3::SKELETON_TRANSFORM, state.skeleton_transform); - state.canvas_shader.set_uniform(CanvasShaderGLES3::SKELETON_TRANSFORM_INVERSE, state.skeleton_transform_inverse); - } - } - - glBindBufferBase(GL_UNIFORM_BUFFER, 1, static_cast<LightInternal *>(light->light_internal.get_data())->ubo); - - if (has_shadow) { - - RasterizerStorageGLES3::CanvasLightShadow *cls = storage->canvas_light_shadow_owner.get(light->shadow_buffer); - glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 2); - glBindTexture(GL_TEXTURE_2D, cls->distance); - - /*canvas_shader.set_uniform(CanvasShaderGLES3::SHADOW_MATRIX,light->shadow_matrix_cache); - canvas_shader.set_uniform(CanvasShaderGLES3::SHADOW_ESM_MULTIPLIER,light->shadow_esm_mult); - canvas_shader.set_uniform(CanvasShaderGLES3::LIGHT_SHADOW_COLOR,light->shadow_color);*/ - } - - glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 1); - RasterizerStorageGLES3::Texture *t = storage->texture_owner.getornull(light->texture); - if (!t) { - glBindTexture(GL_TEXTURE_2D, storage->resources.white_tex); - } else { - t = t->get_ptr(); - - glBindTexture(t->target, t->tex_id); - } - - glActiveTexture(GL_TEXTURE0); - _canvas_item_render_commands(ci, current_clip, reclip); //redraw using light - } - - light = light->next_ptr; - } - - if (light_used) { - - state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_LIGHTING, false); - state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_SHADOWS, false); - state.canvas_shader.set_conditional(CanvasShaderGLES3::SHADOW_FILTER_NEAREST, false); - state.canvas_shader.set_conditional(CanvasShaderGLES3::SHADOW_FILTER_PCF3, false); - state.canvas_shader.set_conditional(CanvasShaderGLES3::SHADOW_FILTER_PCF5, false); - state.canvas_shader.set_conditional(CanvasShaderGLES3::SHADOW_FILTER_PCF7, false); - state.canvas_shader.set_conditional(CanvasShaderGLES3::SHADOW_FILTER_PCF9, false); - state.canvas_shader.set_conditional(CanvasShaderGLES3::SHADOW_FILTER_PCF13, false); - - state.canvas_shader.bind(); - - last_blend_mode = -1; - - /* - //this is set again, so it should not be needed anyway? - state.canvas_item_modulate = unshaded ? ci->final_modulate : Color( - ci->final_modulate.r * p_modulate.r, - ci->final_modulate.g * p_modulate.g, - ci->final_modulate.b * p_modulate.b, - ci->final_modulate.a * p_modulate.a ); - - - state.canvas_shader.set_uniform(CanvasShaderGLES3::MODELVIEW_MATRIX,state.final_transform); - state.canvas_shader.set_uniform(CanvasShaderGLES3::EXTRA_MATRIX,Transform2D()); - state.canvas_shader.set_uniform(CanvasShaderGLES3::FINAL_MODULATE,state.canvas_item_modulate); - - glBlendEquation(GL_FUNC_ADD); - - if (storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]) { - glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - } else { - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - } - - //@TODO RESET canvas_blend_mode - */ - } - } - - if (reclip) { - - glEnable(GL_SCISSOR_TEST); - int y = storage->frame.current_rt->height - (current_clip->final_clip_rect.position.y + current_clip->final_clip_rect.size.y); - if (storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_VFLIP]) - y = current_clip->final_clip_rect.position.y; - glScissor(current_clip->final_clip_rect.position.x, y, current_clip->final_clip_rect.size.width, current_clip->final_clip_rect.size.height); - } - - p_item_list = p_item_list->next; - } - - if (current_clip) { - glDisable(GL_SCISSOR_TEST); - } - //disable states that may have been used - state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_DISTANCE_FIELD, false); - state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_SKELETON, false); - state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_INSTANCE_CUSTOM, false); - state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_PARTICLES, false); - state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_INSTANCING, false); - state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_LIGHTING, false); - state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_SHADOWS, false); -} - -void RasterizerCanvasGLES3::canvas_debug_viewport_shadows(Light *p_lights_with_shadow) { - - Light *light = p_lights_with_shadow; - - canvas_begin(); //reset - glVertexAttrib4f(VS::ARRAY_COLOR, 1, 1, 1, 1); - int h = 10; - int w = storage->frame.current_rt->width; - int ofs = h; - glDisable(GL_BLEND); - - while (light) { - if (light->shadow_buffer.is_valid()) { - - RasterizerStorageGLES3::CanvasLightShadow *sb = storage->canvas_light_shadow_owner.get(light->shadow_buffer); - if (sb) { - glBindTexture(GL_TEXTURE_2D, sb->distance); - draw_generic_textured_rect(Rect2(h, ofs, w - h * 2, h), Rect2(0, 0, 1, 1)); - ofs += h * 2; - } - } - - light = light->shadows_next_ptr; - } - - canvas_end(); -} - -void RasterizerCanvasGLES3::canvas_light_shadow_buffer_update(RID p_buffer, const Transform2D &p_light_xform, int p_light_mask, float p_near, float p_far, LightOccluderInstance *p_occluders, CameraMatrix *p_xform_cache) { - - RasterizerStorageGLES3::CanvasLightShadow *cls = storage->canvas_light_shadow_owner.get(p_buffer); - ERR_FAIL_COND(!cls); - - glDisable(GL_BLEND); - glDisable(GL_SCISSOR_TEST); - glDisable(GL_DITHER); - glDisable(GL_CULL_FACE); - glDepthFunc(GL_LEQUAL); - glEnable(GL_DEPTH_TEST); - glDepthMask(true); - - glBindFramebuffer(GL_FRAMEBUFFER, cls->fbo); - - state.canvas_shadow_shader.bind(); - - glViewport(0, 0, cls->size, cls->height); - glClearDepth(1.0f); - glClearColor(1, 1, 1, 1); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - VS::CanvasOccluderPolygonCullMode cull = VS::CANVAS_OCCLUDER_POLYGON_CULL_DISABLED; - - for (int i = 0; i < 4; i++) { - - //make sure it remains orthogonal, makes easy to read angle later - - Transform light; - light.origin[0] = p_light_xform[2][0]; - light.origin[1] = p_light_xform[2][1]; - light.basis[0][0] = p_light_xform[0][0]; - light.basis[0][1] = p_light_xform[1][0]; - light.basis[1][0] = p_light_xform[0][1]; - light.basis[1][1] = p_light_xform[1][1]; - - //light.basis.scale(Vector3(to_light.elements[0].length(),to_light.elements[1].length(),1)); - - //p_near=1; - CameraMatrix projection; - { - real_t fov = 90; - real_t nearp = p_near; - real_t farp = p_far; - real_t aspect = 1.0; - - real_t ymax = nearp * Math::tan(Math::deg2rad(fov * 0.5)); - real_t ymin = -ymax; - real_t xmin = ymin * aspect; - real_t xmax = ymax * aspect; - - projection.set_frustum(xmin, xmax, ymin, ymax, nearp, farp); - } - - Vector3 cam_target = Basis(Vector3(0, 0, Math_PI * 2 * (i / 4.0))).xform(Vector3(0, 1, 0)); - projection = projection * CameraMatrix(Transform().looking_at(cam_target, Vector3(0, 0, -1)).affine_inverse()); - - state.canvas_shadow_shader.set_uniform(CanvasShadowShaderGLES3::PROJECTION_MATRIX, projection); - state.canvas_shadow_shader.set_uniform(CanvasShadowShaderGLES3::LIGHT_MATRIX, light); - state.canvas_shadow_shader.set_uniform(CanvasShadowShaderGLES3::DISTANCE_NORM, 1.0 / p_far); - - if (i == 0) - *p_xform_cache = projection; - - glViewport(0, (cls->height / 4) * i, cls->size, cls->height / 4); - - LightOccluderInstance *instance = p_occluders; - - while (instance) { - - RasterizerStorageGLES3::CanvasOccluder *cc = storage->canvas_occluder_owner.getornull(instance->polygon_buffer); - if (!cc || cc->len == 0 || !(p_light_mask & instance->light_mask)) { - - instance = instance->next; - continue; - } - - state.canvas_shadow_shader.set_uniform(CanvasShadowShaderGLES3::WORLD_MATRIX, instance->xform_cache); - - VS::CanvasOccluderPolygonCullMode transformed_cull_cache = instance->cull_cache; - - if (transformed_cull_cache != VS::CANVAS_OCCLUDER_POLYGON_CULL_DISABLED && - (p_light_xform.basis_determinant() * instance->xform_cache.basis_determinant()) < 0) { - transformed_cull_cache = - transformed_cull_cache == VS::CANVAS_OCCLUDER_POLYGON_CULL_CLOCKWISE ? - VS::CANVAS_OCCLUDER_POLYGON_CULL_COUNTER_CLOCKWISE : - VS::CANVAS_OCCLUDER_POLYGON_CULL_CLOCKWISE; - } - - if (cull != transformed_cull_cache) { - - cull = transformed_cull_cache; - switch (cull) { - case VS::CANVAS_OCCLUDER_POLYGON_CULL_DISABLED: { - - glDisable(GL_CULL_FACE); - - } break; - case VS::CANVAS_OCCLUDER_POLYGON_CULL_CLOCKWISE: { - - glEnable(GL_CULL_FACE); - glCullFace(GL_FRONT); - } break; - case VS::CANVAS_OCCLUDER_POLYGON_CULL_COUNTER_CLOCKWISE: { - - glEnable(GL_CULL_FACE); - glCullFace(GL_BACK); - - } break; - } - } - - glBindVertexArray(cc->array_id); - glDrawElements(GL_TRIANGLES, cc->len * 3, GL_UNSIGNED_SHORT, 0); - - instance = instance->next; - } - } - - glBindVertexArray(0); -} -void RasterizerCanvasGLES3::reset_canvas() { - - if (storage->frame.current_rt) { - glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->fbo); - glColorMask(1, 1, 1, 1); //don't touch alpha - } - - glBindVertexArray(0); - glDisable(GL_CULL_FACE); - glDisable(GL_DEPTH_TEST); - glDisable(GL_SCISSOR_TEST); - glDisable(GL_DITHER); - glEnable(GL_BLEND); - glBlendEquation(GL_FUNC_ADD); - if (storage->frame.current_rt && storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]) { - glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - } else { - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - } - //glPolygonMode(GL_FRONT_AND_BACK,GL_FILL); - //glLineWidth(1.0); - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - - //use for reading from screen - if (storage->frame.current_rt && !storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_NO_SAMPLING]) { - glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 3); - glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->effects.mip_maps[0].color); - } - - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, storage->resources.white_tex); - - glVertexAttrib4f(VS::ARRAY_COLOR, 1, 1, 1, 1); - - Transform canvas_transform; - - if (storage->frame.current_rt) { - - float csy = 1.0; - if (storage->frame.current_rt && storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_VFLIP]) { - csy = -1.0; - } - canvas_transform.translate(-(storage->frame.current_rt->width / 2.0f), -(storage->frame.current_rt->height / 2.0f), 0.0f); - canvas_transform.scale(Vector3(2.0f / storage->frame.current_rt->width, csy * -2.0f / storage->frame.current_rt->height, 1.0f)); - } else { - Vector2 ssize = OS::get_singleton()->get_window_size(); - canvas_transform.translate(-(ssize.width / 2.0f), -(ssize.height / 2.0f), 0.0f); - canvas_transform.scale(Vector3(2.0f / ssize.width, -2.0f / ssize.height, 1.0f)); - } - - state.vp = canvas_transform; - - store_transform(canvas_transform, state.canvas_item_ubo_data.projection_matrix); - state.canvas_item_ubo_data.time = storage->frame.time[0]; - - glBindBuffer(GL_UNIFORM_BUFFER, state.canvas_item_ubo); - glBufferData(GL_UNIFORM_BUFFER, sizeof(CanvasItemUBO), &state.canvas_item_ubo_data, GL_DYNAMIC_DRAW); - glBindBuffer(GL_UNIFORM_BUFFER, 0); - - state.canvas_texscreen_used = false; -} - -void RasterizerCanvasGLES3::draw_generic_textured_rect(const Rect2 &p_rect, const Rect2 &p_src) { - - state.canvas_shader.set_uniform(CanvasShaderGLES3::DST_RECT, Color(p_rect.position.x, p_rect.position.y, p_rect.size.x, p_rect.size.y)); - state.canvas_shader.set_uniform(CanvasShaderGLES3::SRC_RECT, Color(p_src.position.x, p_src.position.y, p_src.size.x, p_src.size.y)); - state.canvas_shader.set_uniform(CanvasShaderGLES3::CLIP_RECT_UV, false); - - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); -} - -void RasterizerCanvasGLES3::draw_lens_distortion_rect(const Rect2 &p_rect, float p_k1, float p_k2, const Vector2 &p_eye_center, float p_oversample) { - Vector2 half_size; - if (storage->frame.current_rt) { - half_size = Vector2(storage->frame.current_rt->width, storage->frame.current_rt->height); - } else { - half_size = OS::get_singleton()->get_window_size(); - } - half_size *= 0.5; - Vector2 offset((p_rect.position.x - half_size.x) / half_size.x, (p_rect.position.y - half_size.y) / half_size.y); - Vector2 scale(p_rect.size.x / half_size.x, p_rect.size.y / half_size.y); - - float aspect_ratio = p_rect.size.x / p_rect.size.y; - - // setup our lens shader - state.lens_shader.bind(); - state.lens_shader.set_uniform(LensDistortedShaderGLES3::OFFSET, offset); - state.lens_shader.set_uniform(LensDistortedShaderGLES3::SCALE, scale); - state.lens_shader.set_uniform(LensDistortedShaderGLES3::K1, p_k1); - state.lens_shader.set_uniform(LensDistortedShaderGLES3::K2, p_k2); - state.lens_shader.set_uniform(LensDistortedShaderGLES3::EYE_CENTER, p_eye_center); - state.lens_shader.set_uniform(LensDistortedShaderGLES3::UPSCALE, p_oversample); - state.lens_shader.set_uniform(LensDistortedShaderGLES3::ASPECT_RATIO, aspect_ratio); - - glBindBufferBase(GL_UNIFORM_BUFFER, 0, state.canvas_item_ubo); - glBindVertexArray(data.canvas_quad_array); - - // and draw - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - - glBindVertexArray(0); - glBindBufferBase(GL_UNIFORM_BUFFER, 0, 0); -} - -void RasterizerCanvasGLES3::draw_window_margins(int *black_margin, RID *black_image) { - - Vector2 window_size = OS::get_singleton()->get_window_size(); - int window_h = window_size.height; - int window_w = window_size.width; - - glBindFramebuffer(GL_FRAMEBUFFER, RasterizerStorageGLES3::system_fbo); - glViewport(0, 0, window_size.width, window_size.height); - canvas_begin(); - - if (black_image[MARGIN_LEFT].is_valid()) { - _bind_canvas_texture(black_image[MARGIN_LEFT], RID()); - Size2 sz(storage->texture_get_width(black_image[MARGIN_LEFT]), storage->texture_get_height(black_image[MARGIN_LEFT])); - draw_generic_textured_rect(Rect2(0, 0, black_margin[MARGIN_LEFT], window_h), Rect2(0, 0, sz.x, sz.y)); - } else if (black_margin[MARGIN_LEFT]) { - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, storage->resources.black_tex); - - draw_generic_textured_rect(Rect2(0, 0, black_margin[MARGIN_LEFT], window_h), Rect2(0, 0, 1, 1)); - } - - if (black_image[MARGIN_RIGHT].is_valid()) { - _bind_canvas_texture(black_image[MARGIN_RIGHT], RID()); - Size2 sz(storage->texture_get_width(black_image[MARGIN_RIGHT]), storage->texture_get_height(black_image[MARGIN_RIGHT])); - draw_generic_textured_rect(Rect2(window_w - black_margin[MARGIN_RIGHT], 0, black_margin[MARGIN_RIGHT], window_h), Rect2(0, 0, sz.x, sz.y)); - } else if (black_margin[MARGIN_RIGHT]) { - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, storage->resources.black_tex); - - draw_generic_textured_rect(Rect2(window_w - black_margin[MARGIN_RIGHT], 0, black_margin[MARGIN_RIGHT], window_h), Rect2(0, 0, 1, 1)); - } - - if (black_image[MARGIN_TOP].is_valid()) { - _bind_canvas_texture(black_image[MARGIN_TOP], RID()); - - Size2 sz(storage->texture_get_width(black_image[MARGIN_TOP]), storage->texture_get_height(black_image[MARGIN_TOP])); - draw_generic_textured_rect(Rect2(0, 0, window_w, black_margin[MARGIN_TOP]), Rect2(0, 0, sz.x, sz.y)); - - } else if (black_margin[MARGIN_TOP]) { - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, storage->resources.black_tex); - - draw_generic_textured_rect(Rect2(0, 0, window_w, black_margin[MARGIN_TOP]), Rect2(0, 0, 1, 1)); - } - - if (black_image[MARGIN_BOTTOM].is_valid()) { - - _bind_canvas_texture(black_image[MARGIN_BOTTOM], RID()); - - Size2 sz(storage->texture_get_width(black_image[MARGIN_BOTTOM]), storage->texture_get_height(black_image[MARGIN_BOTTOM])); - draw_generic_textured_rect(Rect2(0, window_h - black_margin[MARGIN_BOTTOM], window_w, black_margin[MARGIN_BOTTOM]), Rect2(0, 0, sz.x, sz.y)); - - } else if (black_margin[MARGIN_BOTTOM]) { - - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, storage->resources.black_tex); - - draw_generic_textured_rect(Rect2(0, window_h - black_margin[MARGIN_BOTTOM], window_w, black_margin[MARGIN_BOTTOM]), Rect2(0, 0, 1, 1)); - } -} - -void RasterizerCanvasGLES3::initialize() { - - { - //quad buffers - - glGenBuffers(1, &data.canvas_quad_vertices); - glBindBuffer(GL_ARRAY_BUFFER, data.canvas_quad_vertices); - { - const float qv[8] = { - 0, 0, - 0, 1, - 1, 1, - 1, 0 - }; - - glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 8, qv, GL_STATIC_DRAW); - } - - glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind - - glGenVertexArrays(1, &data.canvas_quad_array); - glBindVertexArray(data.canvas_quad_array); - glBindBuffer(GL_ARRAY_BUFFER, data.canvas_quad_vertices); - glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, 0); - glEnableVertexAttribArray(0); - glBindVertexArray(0); - glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind - } - { - //particle quad buffers - - glGenBuffers(1, &data.particle_quad_vertices); - glBindBuffer(GL_ARRAY_BUFFER, data.particle_quad_vertices); - { - //quad of size 1, with pivot on the center for particles, then regular UVS. Color is general plus fetched from particle - const float qv[16] = { - -0.5, -0.5, - 0.0, 0.0, - -0.5, 0.5, - 0.0, 1.0, - 0.5, 0.5, - 1.0, 1.0, - 0.5, -0.5, - 1.0, 0.0 - }; - - glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 16, qv, GL_STATIC_DRAW); - } - - glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind - - glGenVertexArrays(1, &data.particle_quad_array); - glBindVertexArray(data.particle_quad_array); - glBindBuffer(GL_ARRAY_BUFFER, data.particle_quad_vertices); - glEnableVertexAttribArray(VS::ARRAY_VERTEX); - glVertexAttribPointer(VS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 4, 0); - glEnableVertexAttribArray(VS::ARRAY_TEX_UV); - glVertexAttribPointer(VS::ARRAY_TEX_UV, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 4, CAST_INT_TO_UCHAR_PTR(8)); - glBindVertexArray(0); - glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind - } - { - - uint32_t poly_size = GLOBAL_DEF_RST("rendering/limits/buffers/canvas_polygon_buffer_size_kb", 128); - ProjectSettings::get_singleton()->set_custom_property_info("rendering/limits/buffers/canvas_polygon_buffer_size_kb", PropertyInfo(Variant::INT, "rendering/limits/buffers/canvas_polygon_buffer_size_kb", PROPERTY_HINT_RANGE, "0,256,1,or_greater")); - poly_size *= 1024; //kb - poly_size = MAX(poly_size, (2 + 2 + 4) * 4 * sizeof(float)); - glGenBuffers(1, &data.polygon_buffer); - glBindBuffer(GL_ARRAY_BUFFER, data.polygon_buffer); - glBufferData(GL_ARRAY_BUFFER, poly_size, NULL, GL_DYNAMIC_DRAW); //allocate max size - glBindBuffer(GL_ARRAY_BUFFER, 0); - data.polygon_buffer_size = poly_size; - - //quad arrays - for (int i = 0; i < 4; i++) { - glGenVertexArrays(1, &data.polygon_buffer_quad_arrays[i]); - glBindVertexArray(data.polygon_buffer_quad_arrays[i]); - glBindBuffer(GL_ARRAY_BUFFER, data.polygon_buffer); - - int uv_ofs = 0; - int color_ofs = 0; - int stride = 2 * 4; - - if (i & 1) { //color - color_ofs = stride; - stride += 4 * 4; - } - - if (i & 2) { //uv - uv_ofs = stride; - stride += 2 * 4; - } - - glEnableVertexAttribArray(VS::ARRAY_VERTEX); - glVertexAttribPointer(VS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, stride, NULL); - - if (i & 1) { - glEnableVertexAttribArray(VS::ARRAY_COLOR); - glVertexAttribPointer(VS::ARRAY_COLOR, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(color_ofs)); - } - - if (i & 2) { - glEnableVertexAttribArray(VS::ARRAY_TEX_UV); - glVertexAttribPointer(VS::ARRAY_TEX_UV, 2, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(uv_ofs)); - } - - glBindVertexArray(0); - } - - glGenVertexArrays(1, &data.polygon_buffer_pointer_array); - - uint32_t index_size = GLOBAL_DEF_RST("rendering/limits/buffers/canvas_polygon_index_buffer_size_kb", 128); - ProjectSettings::get_singleton()->set_custom_property_info("rendering/limits/buffers/canvas_polygon_index_buffer_size_kb", PropertyInfo(Variant::INT, "rendering/limits/buffers/canvas_polygon_index_buffer_size_kb", PROPERTY_HINT_RANGE, "0,256,1,or_greater")); - index_size *= 1024; //kb - glGenBuffers(1, &data.polygon_index_buffer); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, data.polygon_index_buffer); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, index_size, NULL, GL_DYNAMIC_DRAW); //allocate max size - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - - data.polygon_index_buffer_size = index_size; - } - - store_transform(Transform(), state.canvas_item_ubo_data.projection_matrix); - - glGenBuffers(1, &state.canvas_item_ubo); - glBindBuffer(GL_UNIFORM_BUFFER, state.canvas_item_ubo); - glBufferData(GL_UNIFORM_BUFFER, sizeof(CanvasItemUBO), &state.canvas_item_ubo_data, GL_DYNAMIC_DRAW); - glBindBuffer(GL_UNIFORM_BUFFER, 0); - - state.canvas_shader.init(); - state.canvas_shader.set_base_material_tex_index(2); - state.canvas_shadow_shader.init(); - state.lens_shader.init(); - - state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_RGBA_SHADOWS, storage->config.use_rgba_2d_shadows); - state.canvas_shadow_shader.set_conditional(CanvasShadowShaderGLES3::USE_RGBA_SHADOWS, storage->config.use_rgba_2d_shadows); - - state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_PIXEL_SNAP, GLOBAL_DEF("rendering/quality/2d/use_pixel_snap", false)); -} - -void RasterizerCanvasGLES3::finalize() { - - glDeleteBuffers(1, &data.canvas_quad_vertices); - glDeleteVertexArrays(1, &data.canvas_quad_array); - - glDeleteBuffers(1, &data.canvas_quad_vertices); - glDeleteVertexArrays(1, &data.canvas_quad_array); - - glDeleteVertexArrays(1, &data.polygon_buffer_pointer_array); -} - -RasterizerCanvasGLES3::RasterizerCanvasGLES3() { -} diff --git a/drivers/gles3/rasterizer_canvas_gles3.h b/drivers/gles3/rasterizer_canvas_gles3.h deleted file mode 100644 index 929867337d..0000000000 --- a/drivers/gles3/rasterizer_canvas_gles3.h +++ /dev/null @@ -1,158 +0,0 @@ -/*************************************************************************/ -/* rasterizer_canvas_gles3.h */ -/*************************************************************************/ -/* 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. */ -/*************************************************************************/ - -#ifndef RASTERIZERCANVASGLES3_H -#define RASTERIZERCANVASGLES3_H - -#include "rasterizer_storage_gles3.h" -#include "servers/visual/rasterizer.h" - -#include "shaders/canvas_shadow.glsl.gen.h" -#include "shaders/lens_distorted.glsl.gen.h" - -class RasterizerSceneGLES3; - -class RasterizerCanvasGLES3 : public RasterizerCanvas { -public: - struct CanvasItemUBO { - - float projection_matrix[16]; - float time; - uint8_t padding[12]; - }; - - RasterizerSceneGLES3 *scene_render; - - struct Data { - - GLuint canvas_quad_vertices; - GLuint canvas_quad_array; - - GLuint polygon_buffer; - GLuint polygon_buffer_quad_arrays[4]; - GLuint polygon_buffer_pointer_array; - GLuint polygon_index_buffer; - - GLuint particle_quad_vertices; - GLuint particle_quad_array; - - uint32_t polygon_buffer_size; - uint32_t polygon_index_buffer_size; - - } data; - - struct State { - CanvasItemUBO canvas_item_ubo_data; - GLuint canvas_item_ubo; - bool canvas_texscreen_used; - CanvasShaderGLES3 canvas_shader; - CanvasShadowShaderGLES3 canvas_shadow_shader; - LensDistortedShaderGLES3 lens_shader; - - bool using_texture_rect; - bool using_ninepatch; - - RID current_tex; - RID current_normal; - RasterizerStorageGLES3::Texture *current_tex_ptr; - - Transform vp; - - Color canvas_item_modulate; - Transform2D extra_matrix; - Transform2D final_transform; - bool using_skeleton; - Transform2D skeleton_transform; - Transform2D skeleton_transform_inverse; - - } state; - - RasterizerStorageGLES3 *storage; - - struct LightInternal : public RID_Data { - - struct UBOData { - - float light_matrix[16]; - float local_matrix[16]; - float shadow_matrix[16]; - float color[4]; - float shadow_color[4]; - float light_pos[2]; - float shadowpixel_size; - float shadow_gradient; - float light_height; - float light_outside_alpha; - float shadow_distance_mult; - uint8_t padding[4]; - } ubo_data; - - GLuint ubo; - }; - - RID_Owner<LightInternal> light_internal_owner; - - virtual RID light_internal_create(); - virtual void light_internal_update(RID p_rid, Light *p_light); - virtual void light_internal_free(RID p_rid); - - virtual void canvas_begin(); - virtual void canvas_end(); - - _FORCE_INLINE_ void _set_texture_rect_mode(bool p_enable, bool p_ninepatch = false); - _FORCE_INLINE_ RasterizerStorageGLES3::Texture *_bind_canvas_texture(const RID &p_texture, const RID &p_normal_map, bool p_force = false); - - _FORCE_INLINE_ void _draw_gui_primitive(int p_points, const Vector2 *p_vertices, const Color *p_colors, const Vector2 *p_uvs); - _FORCE_INLINE_ void _draw_polygon(const int *p_indices, int p_index_count, int p_vertex_count, const Vector2 *p_vertices, const Vector2 *p_uvs, const Color *p_colors, bool p_singlecolor, const int *p_bones, const float *p_weights); - _FORCE_INLINE_ void _draw_generic(GLuint p_primitive, int p_vertex_count, const Vector2 *p_vertices, const Vector2 *p_uvs, const Color *p_colors, bool p_singlecolor); - _FORCE_INLINE_ void _draw_generic_indices(GLuint p_primitive, const int *p_indices, int p_index_count, int p_vertex_count, const Vector2 *p_vertices, const Vector2 *p_uvs, const Color *p_colors, bool p_singlecolor); - - _FORCE_INLINE_ void _canvas_item_render_commands(Item *p_item, Item *current_clip, bool &reclip); - _FORCE_INLINE_ void _copy_texscreen(const Rect2 &p_rect); - - virtual void canvas_render_items(Item *p_item_list, int p_z, const Color &p_modulate, Light *p_light, const Transform2D &p_transform); - virtual void canvas_debug_viewport_shadows(Light *p_lights_with_shadow); - - virtual void canvas_light_shadow_buffer_update(RID p_buffer, const Transform2D &p_light_xform, int p_light_mask, float p_near, float p_far, LightOccluderInstance *p_occluders, CameraMatrix *p_xform_cache); - - virtual void reset_canvas(); - - void draw_generic_textured_rect(const Rect2 &p_rect, const Rect2 &p_src); - void draw_lens_distortion_rect(const Rect2 &p_rect, float p_k1, float p_k2, const Vector2 &p_eye_center, float p_oversample); - - void initialize(); - void finalize(); - - virtual void draw_window_margins(int *black_margin, RID *black_image); - - RasterizerCanvasGLES3(); -}; - -#endif // RASTERIZERCANVASGLES3_H diff --git a/drivers/gles3/rasterizer_gles3.cpp b/drivers/gles3/rasterizer_gles3.cpp deleted file mode 100644 index a24147146f..0000000000 --- a/drivers/gles3/rasterizer_gles3.cpp +++ /dev/null @@ -1,444 +0,0 @@ -/*************************************************************************/ -/* rasterizer_gles3.cpp */ -/*************************************************************************/ -/* 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. */ -/*************************************************************************/ - -#include "rasterizer_gles3.h" - -#include "core/os/os.h" -#include "core/project_settings.h" - -RasterizerStorage *RasterizerGLES3::get_storage() { - - return storage; -} - -RasterizerCanvas *RasterizerGLES3::get_canvas() { - - return canvas; -} - -RasterizerScene *RasterizerGLES3::get_scene() { - - return scene; -} - -#define _EXT_DEBUG_OUTPUT_SYNCHRONOUS_ARB 0x8242 -#define _EXT_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH_ARB 0x8243 -#define _EXT_DEBUG_CALLBACK_FUNCTION_ARB 0x8244 -#define _EXT_DEBUG_CALLBACK_USER_PARAM_ARB 0x8245 -#define _EXT_DEBUG_SOURCE_API_ARB 0x8246 -#define _EXT_DEBUG_SOURCE_WINDOW_SYSTEM_ARB 0x8247 -#define _EXT_DEBUG_SOURCE_SHADER_COMPILER_ARB 0x8248 -#define _EXT_DEBUG_SOURCE_THIRD_PARTY_ARB 0x8249 -#define _EXT_DEBUG_SOURCE_APPLICATION_ARB 0x824A -#define _EXT_DEBUG_SOURCE_OTHER_ARB 0x824B -#define _EXT_DEBUG_TYPE_ERROR_ARB 0x824C -#define _EXT_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB 0x824D -#define _EXT_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB 0x824E -#define _EXT_DEBUG_TYPE_PORTABILITY_ARB 0x824F -#define _EXT_DEBUG_TYPE_PERFORMANCE_ARB 0x8250 -#define _EXT_DEBUG_TYPE_OTHER_ARB 0x8251 -#define _EXT_MAX_DEBUG_MESSAGE_LENGTH_ARB 0x9143 -#define _EXT_MAX_DEBUG_LOGGED_MESSAGES_ARB 0x9144 -#define _EXT_DEBUG_LOGGED_MESSAGES_ARB 0x9145 -#define _EXT_DEBUG_SEVERITY_HIGH_ARB 0x9146 -#define _EXT_DEBUG_SEVERITY_MEDIUM_ARB 0x9147 -#define _EXT_DEBUG_SEVERITY_LOW_ARB 0x9148 -#define _EXT_DEBUG_OUTPUT 0x92E0 - -#if defined(MINGW_ENABLED) || defined(_MSC_VER) -#define strcpy strcpy_s -#endif - -#ifdef GLAD_ENABLED -// Restricting to GLAD as only used in initialize() with GLAD_GL_ARB_debug_output -static void GLAPIENTRY _gl_debug_print(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message, const GLvoid *userParam) { - - if (type == _EXT_DEBUG_TYPE_OTHER_ARB) - return; - - if (type == _EXT_DEBUG_TYPE_PERFORMANCE_ARB) - return; //these are ultimately annoying, so removing for now - - char debSource[256], debType[256], debSev[256]; - if (source == _EXT_DEBUG_SOURCE_API_ARB) - strcpy(debSource, "OpenGL"); - else if (source == _EXT_DEBUG_SOURCE_WINDOW_SYSTEM_ARB) - strcpy(debSource, "Windows"); - else if (source == _EXT_DEBUG_SOURCE_SHADER_COMPILER_ARB) - strcpy(debSource, "Shader Compiler"); - else if (source == _EXT_DEBUG_SOURCE_THIRD_PARTY_ARB) - strcpy(debSource, "Third Party"); - else if (source == _EXT_DEBUG_SOURCE_APPLICATION_ARB) - strcpy(debSource, "Application"); - else if (source == _EXT_DEBUG_SOURCE_OTHER_ARB) - strcpy(debSource, "Other"); - - if (type == _EXT_DEBUG_TYPE_ERROR_ARB) - strcpy(debType, "Error"); - else if (type == _EXT_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB) - strcpy(debType, "Deprecated behavior"); - else if (type == _EXT_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB) - strcpy(debType, "Undefined behavior"); - else if (type == _EXT_DEBUG_TYPE_PORTABILITY_ARB) - strcpy(debType, "Portability"); - else if (type == _EXT_DEBUG_TYPE_PERFORMANCE_ARB) - strcpy(debType, "Performance"); - - if (severity == _EXT_DEBUG_SEVERITY_HIGH_ARB) - strcpy(debSev, "High"); - else if (severity == _EXT_DEBUG_SEVERITY_MEDIUM_ARB) - strcpy(debSev, "Medium"); - else if (severity == _EXT_DEBUG_SEVERITY_LOW_ARB) - strcpy(debSev, "Low"); - - String output = String() + "GL ERROR: Source: " + debSource + "\tType: " + debType + "\tID: " + itos(id) + "\tSeverity: " + debSev + "\tMessage: " + message; - - ERR_PRINTS(output); -} -#endif // GLAD_ENABLED - -typedef void (*DEBUGPROCARB)(GLenum source, - GLenum type, - GLuint id, - GLenum severity, - GLsizei length, - const char *message, - const void *userParam); - -typedef void (*DebugMessageCallbackARB)(DEBUGPROCARB callback, const void *userParam); - -Error RasterizerGLES3::is_viable() { - -#ifdef GLAD_ENABLED - if (!gladLoadGL()) { - ERR_PRINT("Error initializing GLAD"); - return ERR_UNAVAILABLE; - } - -// GLVersion seems to be used for both GL and GL ES, so we need different version checks for them -#ifdef OPENGL_ENABLED // OpenGL 3.3 Core Profile required - if (GLVersion.major < 3 || (GLVersion.major == 3 && GLVersion.minor < 3)) { -#else // OpenGL ES 3.0 - if (GLVersion.major < 3) { -#endif - return ERR_UNAVAILABLE; - } - -#endif // GLAD_ENABLED - return OK; -} - -void RasterizerGLES3::initialize() { - - print_verbose("Using GLES3 video driver"); - -#ifdef GLAD_ENABLED - if (OS::get_singleton()->is_stdout_verbose()) { - if (GLAD_GL_ARB_debug_output) { - glEnable(_EXT_DEBUG_OUTPUT_SYNCHRONOUS_ARB); - glDebugMessageCallbackARB(_gl_debug_print, NULL); - glEnable(_EXT_DEBUG_OUTPUT); - } else { - print_line("OpenGL debugging not supported!"); - } - } -#endif // GLAD_ENABLED - - /* // For debugging - if (GLAD_GL_ARB_debug_output) { - glDebugMessageControlARB(GL_DEBUG_SOURCE_API_ARB,GL_DEBUG_TYPE_ERROR_ARB,GL_DEBUG_SEVERITY_HIGH_ARB,0,NULL,GL_TRUE); - glDebugMessageControlARB(GL_DEBUG_SOURCE_API_ARB,GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB,GL_DEBUG_SEVERITY_HIGH_ARB,0,NULL,GL_TRUE); - glDebugMessageControlARB(GL_DEBUG_SOURCE_API_ARB,GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB,GL_DEBUG_SEVERITY_HIGH_ARB,0,NULL,GL_TRUE); - glDebugMessageControlARB(GL_DEBUG_SOURCE_API_ARB,GL_DEBUG_TYPE_PORTABILITY_ARB,GL_DEBUG_SEVERITY_HIGH_ARB,0,NULL,GL_TRUE); - glDebugMessageControlARB(GL_DEBUG_SOURCE_API_ARB,GL_DEBUG_TYPE_PERFORMANCE_ARB,GL_DEBUG_SEVERITY_HIGH_ARB,0,NULL,GL_TRUE); - glDebugMessageControlARB(GL_DEBUG_SOURCE_API_ARB,GL_DEBUG_TYPE_OTHER_ARB,GL_DEBUG_SEVERITY_HIGH_ARB,0,NULL,GL_TRUE); - glDebugMessageInsertARB( - GL_DEBUG_SOURCE_API_ARB, - GL_DEBUG_TYPE_OTHER_ARB, 1, - GL_DEBUG_SEVERITY_HIGH_ARB,5, "hello"); - } - */ - - print_line("OpenGL ES 3.0 Renderer: " + VisualServer::get_singleton()->get_video_adapter_name()); - storage->initialize(); - canvas->initialize(); - scene->initialize(); -} - -void RasterizerGLES3::begin_frame(double frame_step) { - - time_total += frame_step; - - if (frame_step == 0) { - //to avoid hiccups - frame_step = 0.001; - } - - double time_roll_over = GLOBAL_GET("rendering/limits/time/time_rollover_secs"); - if (time_total > time_roll_over) - time_total = 0; //roll over every day (should be customz - - storage->frame.time[0] = time_total; - storage->frame.time[1] = Math::fmod(time_total, 3600); - storage->frame.time[2] = Math::fmod(time_total, 900); - storage->frame.time[3] = Math::fmod(time_total, 60); - storage->frame.count++; - storage->frame.delta = frame_step; - - storage->update_dirty_resources(); - - storage->info.render_final = storage->info.render; - storage->info.render.reset(); - - scene->iteration(); -} - -void RasterizerGLES3::set_current_render_target(RID p_render_target) { - - if (!p_render_target.is_valid() && storage->frame.current_rt && storage->frame.clear_request) { - //handle pending clear request, if the framebuffer was not cleared - glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->fbo); - - glClearColor( - storage->frame.clear_request_color.r, - storage->frame.clear_request_color.g, - storage->frame.clear_request_color.b, - storage->frame.clear_request_color.a); - - glClear(GL_COLOR_BUFFER_BIT); - } - - if (p_render_target.is_valid()) { - RasterizerStorageGLES3::RenderTarget *rt = storage->render_target_owner.getornull(p_render_target); - storage->frame.current_rt = rt; - ERR_FAIL_COND(!rt); - storage->frame.clear_request = false; - - glViewport(0, 0, rt->width, rt->height); - - } else { - storage->frame.current_rt = NULL; - storage->frame.clear_request = false; - glViewport(0, 0, OS::get_singleton()->get_window_size().width, OS::get_singleton()->get_window_size().height); - glBindFramebuffer(GL_FRAMEBUFFER, RasterizerStorageGLES3::system_fbo); - } -} - -void RasterizerGLES3::restore_render_target(bool p_3d_was_drawn) { - - ERR_FAIL_COND(storage->frame.current_rt == NULL); - RasterizerStorageGLES3::RenderTarget *rt = storage->frame.current_rt; - if (p_3d_was_drawn && rt->external.fbo != 0) { - // our external render buffer is now leading, render 2d into that. - glBindFramebuffer(GL_FRAMEBUFFER, rt->external.fbo); - } else { - glBindFramebuffer(GL_FRAMEBUFFER, rt->fbo); - } - glViewport(0, 0, rt->width, rt->height); -} - -void RasterizerGLES3::clear_render_target(const Color &p_color) { - - ERR_FAIL_COND(!storage->frame.current_rt); - - storage->frame.clear_request = true; - storage->frame.clear_request_color = p_color; -} - -void RasterizerGLES3::set_boot_image(const Ref<Image> &p_image, const Color &p_color, bool p_scale, bool p_use_filter) { - - if (p_image.is_null() || p_image->empty()) - return; - - begin_frame(0.0); - - int window_w = OS::get_singleton()->get_video_mode(0).width; - int window_h = OS::get_singleton()->get_video_mode(0).height; - - glBindFramebuffer(GL_FRAMEBUFFER, RasterizerStorageGLES3::system_fbo); - glViewport(0, 0, window_w, window_h); - glDisable(GL_BLEND); - glDepthMask(GL_FALSE); - if (OS::get_singleton()->get_window_per_pixel_transparency_enabled()) { - glClearColor(0.0, 0.0, 0.0, 0.0); - } else { - glClearColor(p_color.r, p_color.g, p_color.b, 1.0); - } - glClear(GL_COLOR_BUFFER_BIT); - canvas->canvas_begin(); - - RID texture = storage->texture_create(); - storage->texture_allocate(texture, p_image->get_width(), p_image->get_height(), 0, p_image->get_format(), VS::TEXTURE_TYPE_2D, p_use_filter ? VS::TEXTURE_FLAG_FILTER : 0); - storage->texture_set_data(texture, p_image); - - Rect2 imgrect(0, 0, p_image->get_width(), p_image->get_height()); - Rect2 screenrect; - if (p_scale) { - - if (window_w > window_h) { - //scale horizontally - screenrect.size.y = window_h; - screenrect.size.x = imgrect.size.x * window_h / imgrect.size.y; - screenrect.position.x = (window_w - screenrect.size.x) / 2; - - } else { - //scale vertically - screenrect.size.x = window_w; - screenrect.size.y = imgrect.size.y * window_w / imgrect.size.x; - screenrect.position.y = (window_h - screenrect.size.y) / 2; - } - } else { - - screenrect = imgrect; - screenrect.position += ((Size2(window_w, window_h) - screenrect.size) / 2.0).floor(); - } - - RasterizerStorageGLES3::Texture *t = storage->texture_owner.get(texture); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, t->tex_id); - canvas->draw_generic_textured_rect(screenrect, Rect2(0, 0, 1, 1)); - glBindTexture(GL_TEXTURE_2D, 0); - canvas->canvas_end(); - - storage->free(texture); // free since it's only one frame that stays there - - end_frame(true); -} - -void RasterizerGLES3::blit_render_target_to_screen(RID p_render_target, const Rect2 &p_screen_rect, int p_screen) { - - ERR_FAIL_COND(storage->frame.current_rt); - - RasterizerStorageGLES3::RenderTarget *rt = storage->render_target_owner.getornull(p_render_target); - ERR_FAIL_COND(!rt); - - Size2 win_size = OS::get_singleton()->get_window_size(); - if (rt->external.fbo != 0) { - glBindFramebuffer(GL_READ_FRAMEBUFFER, rt->external.fbo); - } else { - glBindFramebuffer(GL_READ_FRAMEBUFFER, rt->fbo); - } - glReadBuffer(GL_COLOR_ATTACHMENT0); - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, RasterizerStorageGLES3::system_fbo); - glBlitFramebuffer(0, 0, rt->width, rt->height, p_screen_rect.position.x, win_size.height - p_screen_rect.position.y - p_screen_rect.size.height, p_screen_rect.position.x + p_screen_rect.size.width, win_size.height - p_screen_rect.position.y, GL_COLOR_BUFFER_BIT, GL_NEAREST); -} - -void RasterizerGLES3::output_lens_distorted_to_screen(RID p_render_target, const Rect2 &p_screen_rect, float p_k1, float p_k2, const Vector2 &p_eye_center, float p_oversample) { - ERR_FAIL_COND(storage->frame.current_rt); - - RasterizerStorageGLES3::RenderTarget *rt = storage->render_target_owner.getornull(p_render_target); - ERR_FAIL_COND(!rt); - - glDisable(GL_BLEND); - - // render to our framebuffer - glBindFramebuffer(GL_FRAMEBUFFER, RasterizerStorageGLES3::system_fbo); - - // output our texture - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, rt->color); - - canvas->draw_lens_distortion_rect(p_screen_rect, p_k1, p_k2, p_eye_center, p_oversample); - - glBindTexture(GL_TEXTURE_2D, 0); -} - -void RasterizerGLES3::end_frame(bool p_swap_buffers) { - - if (OS::get_singleton()->is_layered_allowed()) { - if (OS::get_singleton()->get_window_per_pixel_transparency_enabled()) { -#if (defined WINDOWS_ENABLED) && !(defined UWP_ENABLED) - Size2 wndsize = OS::get_singleton()->get_layered_buffer_size(); - uint8_t *data = OS::get_singleton()->get_layered_buffer_data(); - if (data) { - glReadPixels(0, 0, wndsize.x, wndsize.y, GL_BGRA, GL_UNSIGNED_BYTE, data); - OS::get_singleton()->swap_layered_buffer(); - - return; - } -#endif - } else { - //clear alpha - glColorMask(false, false, false, true); - glClearColor(0, 0, 0, 1); - glClear(GL_COLOR_BUFFER_BIT); - glColorMask(true, true, true, true); - } - } - - if (p_swap_buffers) - OS::get_singleton()->swap_buffers(); - else - glFinish(); -} - -void RasterizerGLES3::finalize() { - - storage->finalize(); - canvas->finalize(); -} - -Rasterizer *RasterizerGLES3::_create_current() { - - return memnew(RasterizerGLES3); -} - -void RasterizerGLES3::make_current() { - _create_func = _create_current; -} - -void RasterizerGLES3::register_config() { - - GLOBAL_DEF("rendering/quality/filters/anisotropic_filter_level", 4); - ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/filters/anisotropic_filter_level", PropertyInfo(Variant::INT, "rendering/quality/filters/anisotropic_filter_level", PROPERTY_HINT_RANGE, "1,16,1")); - GLOBAL_DEF("rendering/limits/time/time_rollover_secs", 3600); - ProjectSettings::get_singleton()->set_custom_property_info("rendering/limits/time/time_rollover_secs", PropertyInfo(Variant::REAL, "rendering/limits/time/time_rollover_secs", PROPERTY_HINT_RANGE, "0,10000,1,or_greater")); -} - -RasterizerGLES3::RasterizerGLES3() { - - storage = memnew(RasterizerStorageGLES3); - canvas = memnew(RasterizerCanvasGLES3); - scene = memnew(RasterizerSceneGLES3); - canvas->storage = storage; - canvas->scene_render = scene; - storage->canvas = canvas; - scene->storage = storage; - storage->scene = scene; - - time_total = 0; -} - -RasterizerGLES3::~RasterizerGLES3() { - - memdelete(storage); - memdelete(canvas); - memdelete(scene); -} diff --git a/drivers/gles3/rasterizer_gles3.h b/drivers/gles3/rasterizer_gles3.h deleted file mode 100644 index de7c1ab7e1..0000000000 --- a/drivers/gles3/rasterizer_gles3.h +++ /dev/null @@ -1,76 +0,0 @@ -/*************************************************************************/ -/* rasterizer_gles3.h */ -/*************************************************************************/ -/* 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. */ -/*************************************************************************/ - -#ifndef RASTERIZERGLES3_H -#define RASTERIZERGLES3_H - -#include "rasterizer_canvas_gles3.h" -#include "rasterizer_scene_gles3.h" -#include "rasterizer_storage_gles3.h" -#include "servers/visual/rasterizer.h" - -class RasterizerGLES3 : public Rasterizer { - - static Rasterizer *_create_current(); - - RasterizerStorageGLES3 *storage; - RasterizerCanvasGLES3 *canvas; - RasterizerSceneGLES3 *scene; - - double time_total; - -public: - virtual RasterizerStorage *get_storage(); - virtual RasterizerCanvas *get_canvas(); - virtual RasterizerScene *get_scene(); - - virtual void set_boot_image(const Ref<Image> &p_image, const Color &p_color, bool p_scale, bool p_use_filter = true); - - virtual void initialize(); - virtual void begin_frame(double frame_step); - virtual void set_current_render_target(RID p_render_target); - virtual void restore_render_target(bool p_3d_was_drawn); - virtual void clear_render_target(const Color &p_color); - virtual void blit_render_target_to_screen(RID p_render_target, const Rect2 &p_screen_rect, int p_screen = 0); - virtual void output_lens_distorted_to_screen(RID p_render_target, const Rect2 &p_screen_rect, float p_k1, float p_k2, const Vector2 &p_eye_center, float p_oversample); - virtual void end_frame(bool p_swap_buffers); - virtual void finalize(); - - static Error is_viable(); - static void make_current(); - static void register_config(); - - virtual bool is_low_end() const { return false; } - - RasterizerGLES3(); - ~RasterizerGLES3(); -}; - -#endif // RASTERIZERGLES3_H diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp deleted file mode 100644 index 27173d317b..0000000000 --- a/drivers/gles3/rasterizer_scene_gles3.cpp +++ /dev/null @@ -1,5346 +0,0 @@ -/*************************************************************************/ -/* rasterizer_scene_gles3.cpp */ -/*************************************************************************/ -/* 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. */ -/*************************************************************************/ - -#include "rasterizer_scene_gles3.h" - -#include "core/math/math_funcs.h" -#include "core/os/os.h" -#include "core/project_settings.h" -#include "rasterizer_canvas_gles3.h" -#include "servers/camera/camera_feed.h" -#include "servers/visual/visual_server_raster.h" - -#ifndef GLES_OVER_GL -#define glClearDepth glClearDepthf -#endif - -static const GLenum _cube_side_enum[6] = { - - GL_TEXTURE_CUBE_MAP_NEGATIVE_X, - GL_TEXTURE_CUBE_MAP_POSITIVE_X, - GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, - GL_TEXTURE_CUBE_MAP_POSITIVE_Y, - GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, - GL_TEXTURE_CUBE_MAP_POSITIVE_Z, - -}; - -static _FORCE_INLINE_ void store_transform(const Transform &p_mtx, float *p_array) { - p_array[0] = p_mtx.basis.elements[0][0]; - p_array[1] = p_mtx.basis.elements[1][0]; - p_array[2] = p_mtx.basis.elements[2][0]; - p_array[3] = 0; - p_array[4] = p_mtx.basis.elements[0][1]; - p_array[5] = p_mtx.basis.elements[1][1]; - p_array[6] = p_mtx.basis.elements[2][1]; - p_array[7] = 0; - p_array[8] = p_mtx.basis.elements[0][2]; - p_array[9] = p_mtx.basis.elements[1][2]; - p_array[10] = p_mtx.basis.elements[2][2]; - p_array[11] = 0; - p_array[12] = p_mtx.origin.x; - p_array[13] = p_mtx.origin.y; - p_array[14] = p_mtx.origin.z; - p_array[15] = 1; -} - -static _FORCE_INLINE_ void store_camera(const CameraMatrix &p_mtx, float *p_array) { - - for (int i = 0; i < 4; i++) { - for (int j = 0; j < 4; j++) { - - p_array[i * 4 + j] = p_mtx.matrix[i][j]; - } - } -} - -/* SHADOW ATLAS API */ - -RID RasterizerSceneGLES3::shadow_atlas_create() { - - ShadowAtlas *shadow_atlas = memnew(ShadowAtlas); - shadow_atlas->fbo = 0; - shadow_atlas->depth = 0; - shadow_atlas->size = 0; - shadow_atlas->smallest_subdiv = 0; - - for (int i = 0; i < 4; i++) { - shadow_atlas->size_order[i] = i; - } - - return shadow_atlas_owner.make_rid(shadow_atlas); -} - -void RasterizerSceneGLES3::shadow_atlas_set_size(RID p_atlas, int p_size) { - - ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_atlas); - ERR_FAIL_COND(!shadow_atlas); - ERR_FAIL_COND(p_size < 0); - - p_size = next_power_of_2(p_size); - - if (p_size == shadow_atlas->size) - return; - - // erasing atlas - if (shadow_atlas->fbo) { - glDeleteTextures(1, &shadow_atlas->depth); - glDeleteFramebuffers(1, &shadow_atlas->fbo); - - shadow_atlas->depth = 0; - shadow_atlas->fbo = 0; - } - for (int i = 0; i < 4; i++) { - //clear subdivisions - shadow_atlas->quadrants[i].shadows.resize(0); - shadow_atlas->quadrants[i].shadows.resize(1 << shadow_atlas->quadrants[i].subdivision); - } - - //erase shadow atlas reference from lights - for (Map<RID, uint32_t>::Element *E = shadow_atlas->shadow_owners.front(); E; E = E->next()) { - LightInstance *li = light_instance_owner.getornull(E->key()); - ERR_CONTINUE(!li); - li->shadow_atlases.erase(p_atlas); - } - - //clear owners - shadow_atlas->shadow_owners.clear(); - - shadow_atlas->size = p_size; - - if (shadow_atlas->size) { - glGenFramebuffers(1, &shadow_atlas->fbo); - glBindFramebuffer(GL_FRAMEBUFFER, shadow_atlas->fbo); - - // Create a texture for storing the depth - glActiveTexture(GL_TEXTURE0); - glGenTextures(1, &shadow_atlas->depth); - glBindTexture(GL_TEXTURE_2D, shadow_atlas->depth); - glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, shadow_atlas->size, shadow_atlas->size, 0, - GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, - GL_TEXTURE_2D, shadow_atlas->depth, 0); - - glViewport(0, 0, shadow_atlas->size, shadow_atlas->size); - glClearDepth(0.0f); - glClear(GL_DEPTH_BUFFER_BIT); - - glBindFramebuffer(GL_FRAMEBUFFER, 0); - } -} - -void RasterizerSceneGLES3::shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision) { - - ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_atlas); - ERR_FAIL_COND(!shadow_atlas); - ERR_FAIL_INDEX(p_quadrant, 4); - ERR_FAIL_INDEX(p_subdivision, 16384); - - uint32_t subdiv = next_power_of_2(p_subdivision); - if (subdiv & 0xaaaaaaaa) { //sqrt(subdiv) must be integer - subdiv <<= 1; - } - - subdiv = int(Math::sqrt((float)subdiv)); - - //obtain the number that will be x*x - - if (shadow_atlas->quadrants[p_quadrant].subdivision == subdiv) - return; - - //erase all data from quadrant - for (int i = 0; i < shadow_atlas->quadrants[p_quadrant].shadows.size(); i++) { - - if (shadow_atlas->quadrants[p_quadrant].shadows[i].owner.is_valid()) { - shadow_atlas->shadow_owners.erase(shadow_atlas->quadrants[p_quadrant].shadows[i].owner); - LightInstance *li = light_instance_owner.getornull(shadow_atlas->quadrants[p_quadrant].shadows[i].owner); - ERR_CONTINUE(!li); - li->shadow_atlases.erase(p_atlas); - } - } - - shadow_atlas->quadrants[p_quadrant].shadows.resize(0); - shadow_atlas->quadrants[p_quadrant].shadows.resize(subdiv * subdiv); - shadow_atlas->quadrants[p_quadrant].subdivision = subdiv; - - //cache the smallest subdiv (for faster allocation in light update) - - shadow_atlas->smallest_subdiv = 1 << 30; - - for (int i = 0; i < 4; i++) { - if (shadow_atlas->quadrants[i].subdivision) { - shadow_atlas->smallest_subdiv = MIN(shadow_atlas->smallest_subdiv, shadow_atlas->quadrants[i].subdivision); - } - } - - if (shadow_atlas->smallest_subdiv == 1 << 30) { - shadow_atlas->smallest_subdiv = 0; - } - - //resort the size orders, simple bublesort for 4 elements.. - - int swaps = 0; - do { - swaps = 0; - - for (int i = 0; i < 3; i++) { - if (shadow_atlas->quadrants[shadow_atlas->size_order[i]].subdivision < shadow_atlas->quadrants[shadow_atlas->size_order[i + 1]].subdivision) { - SWAP(shadow_atlas->size_order[i], shadow_atlas->size_order[i + 1]); - swaps++; - } - } - } while (swaps > 0); -} - -bool RasterizerSceneGLES3::_shadow_atlas_find_shadow(ShadowAtlas *shadow_atlas, int *p_in_quadrants, int p_quadrant_count, int p_current_subdiv, uint64_t p_tick, int &r_quadrant, int &r_shadow) { - - for (int i = p_quadrant_count - 1; i >= 0; i--) { - - int qidx = p_in_quadrants[i]; - - if (shadow_atlas->quadrants[qidx].subdivision == (uint32_t)p_current_subdiv) { - return false; - } - - //look for an empty space - int sc = shadow_atlas->quadrants[qidx].shadows.size(); - ShadowAtlas::Quadrant::Shadow *sarr = shadow_atlas->quadrants[qidx].shadows.ptrw(); - - int found_free_idx = -1; //found a free one - int found_used_idx = -1; //found existing one, must steal it - uint64_t min_pass = 0; // pass of the existing one, try to use the least recently used one (LRU fashion) - - for (int j = 0; j < sc; j++) { - if (!sarr[j].owner.is_valid()) { - found_free_idx = j; - break; - } - - LightInstance *sli = light_instance_owner.getornull(sarr[j].owner); - ERR_CONTINUE(!sli); - - if (sli->last_scene_pass != scene_pass) { - - //was just allocated, don't kill it so soon, wait a bit.. - if (p_tick - sarr[j].alloc_tick < shadow_atlas_realloc_tolerance_msec) - continue; - - if (found_used_idx == -1 || sli->last_scene_pass < min_pass) { - found_used_idx = j; - min_pass = sli->last_scene_pass; - } - } - } - - if (found_free_idx == -1 && found_used_idx == -1) - continue; //nothing found - - if (found_free_idx == -1 && found_used_idx != -1) { - found_free_idx = found_used_idx; - } - - r_quadrant = qidx; - r_shadow = found_free_idx; - - return true; - } - - return false; -} - -bool RasterizerSceneGLES3::shadow_atlas_update_light(RID p_atlas, RID p_light_intance, float p_coverage, uint64_t p_light_version) { - - ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_atlas); - ERR_FAIL_COND_V(!shadow_atlas, false); - - LightInstance *li = light_instance_owner.getornull(p_light_intance); - ERR_FAIL_COND_V(!li, false); - - if (shadow_atlas->size == 0 || shadow_atlas->smallest_subdiv == 0) { - return false; - } - - uint32_t quad_size = shadow_atlas->size >> 1; - int desired_fit = MIN(quad_size / shadow_atlas->smallest_subdiv, next_power_of_2(quad_size * p_coverage)); - - int valid_quadrants[4]; - int valid_quadrant_count = 0; - int best_size = -1; //best size found - int best_subdiv = -1; //subdiv for the best size - - //find the quadrants this fits into, and the best possible size it can fit into - for (int i = 0; i < 4; i++) { - int q = shadow_atlas->size_order[i]; - int sd = shadow_atlas->quadrants[q].subdivision; - if (sd == 0) - continue; //unused - - int max_fit = quad_size / sd; - - if (best_size != -1 && max_fit > best_size) - break; //too large - - valid_quadrants[valid_quadrant_count++] = q; - best_subdiv = sd; - - if (max_fit >= desired_fit) { - best_size = max_fit; - } - } - - ERR_FAIL_COND_V(valid_quadrant_count == 0, false); - - uint64_t tick = OS::get_singleton()->get_ticks_msec(); - - //see if it already exists - - if (shadow_atlas->shadow_owners.has(p_light_intance)) { - //it does! - uint32_t key = shadow_atlas->shadow_owners[p_light_intance]; - uint32_t q = (key >> ShadowAtlas::QUADRANT_SHIFT) & 0x3; - uint32_t s = key & ShadowAtlas::SHADOW_INDEX_MASK; - - bool should_realloc = shadow_atlas->quadrants[q].subdivision != (uint32_t)best_subdiv && (shadow_atlas->quadrants[q].shadows[s].alloc_tick - tick > shadow_atlas_realloc_tolerance_msec); - bool should_redraw = shadow_atlas->quadrants[q].shadows[s].version != p_light_version; - - if (!should_realloc) { - shadow_atlas->quadrants[q].shadows.write[s].version = p_light_version; - //already existing, see if it should redraw or it's just OK - return should_redraw; - } - - int new_quadrant, new_shadow; - - //find a better place - if (_shadow_atlas_find_shadow(shadow_atlas, valid_quadrants, valid_quadrant_count, shadow_atlas->quadrants[q].subdivision, tick, new_quadrant, new_shadow)) { - //found a better place! - ShadowAtlas::Quadrant::Shadow *sh = &shadow_atlas->quadrants[new_quadrant].shadows.write[new_shadow]; - if (sh->owner.is_valid()) { - //is taken, but is invalid, erasing it - shadow_atlas->shadow_owners.erase(sh->owner); - LightInstance *sli = light_instance_owner.get(sh->owner); - sli->shadow_atlases.erase(p_atlas); - } - - //erase previous - shadow_atlas->quadrants[q].shadows.write[s].version = 0; - shadow_atlas->quadrants[q].shadows.write[s].owner = RID(); - - sh->owner = p_light_intance; - sh->alloc_tick = tick; - sh->version = p_light_version; - li->shadow_atlases.insert(p_atlas); - - //make new key - key = new_quadrant << ShadowAtlas::QUADRANT_SHIFT; - key |= new_shadow; - //update it in map - shadow_atlas->shadow_owners[p_light_intance] = key; - //make it dirty, as it should redraw anyway - return true; - } - - //no better place for this shadow found, keep current - - //already existing, see if it should redraw or it's just OK - - shadow_atlas->quadrants[q].shadows.write[s].version = p_light_version; - - return should_redraw; - } - - int new_quadrant, new_shadow; - - //find a better place - if (_shadow_atlas_find_shadow(shadow_atlas, valid_quadrants, valid_quadrant_count, -1, tick, new_quadrant, new_shadow)) { - //found a better place! - ShadowAtlas::Quadrant::Shadow *sh = &shadow_atlas->quadrants[new_quadrant].shadows.write[new_shadow]; - if (sh->owner.is_valid()) { - //is taken, but is invalid, erasing it - shadow_atlas->shadow_owners.erase(sh->owner); - LightInstance *sli = light_instance_owner.get(sh->owner); - sli->shadow_atlases.erase(p_atlas); - } - - sh->owner = p_light_intance; - sh->alloc_tick = tick; - sh->version = p_light_version; - li->shadow_atlases.insert(p_atlas); - - //make new key - uint32_t key = new_quadrant << ShadowAtlas::QUADRANT_SHIFT; - key |= new_shadow; - //update it in map - shadow_atlas->shadow_owners[p_light_intance] = key; - //make it dirty, as it should redraw anyway - - return true; - } - - //no place to allocate this light, apologies - - return false; -} - -void RasterizerSceneGLES3::set_directional_shadow_count(int p_count) { - - directional_shadow.light_count = p_count; - directional_shadow.current_light = 0; -} - -int RasterizerSceneGLES3::get_directional_light_shadow_size(RID p_light_intance) { - - ERR_FAIL_COND_V(directional_shadow.light_count == 0, 0); - - int shadow_size; - - if (directional_shadow.light_count == 1) { - shadow_size = directional_shadow.size; - } else { - shadow_size = directional_shadow.size / 2; //more than 4 not supported anyway - } - - LightInstance *light_instance = light_instance_owner.getornull(p_light_intance); - ERR_FAIL_COND_V(!light_instance, 0); - - switch (light_instance->light_ptr->directional_shadow_mode) { - case VS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL: - break; //none - case VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS: - case VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS: shadow_size /= 2; break; - } - - return shadow_size; -} -////////////////////////////////////////////////////// - -RID RasterizerSceneGLES3::reflection_atlas_create() { - - ReflectionAtlas *reflection_atlas = memnew(ReflectionAtlas); - reflection_atlas->subdiv = 0; - reflection_atlas->color = 0; - reflection_atlas->size = 0; - for (int i = 0; i < 6; i++) { - reflection_atlas->fbo[i] = 0; - } - - return reflection_atlas_owner.make_rid(reflection_atlas); -} - -void RasterizerSceneGLES3::reflection_atlas_set_size(RID p_ref_atlas, int p_size) { - - ReflectionAtlas *reflection_atlas = reflection_atlas_owner.getornull(p_ref_atlas); - ERR_FAIL_COND(!reflection_atlas); - - int size = next_power_of_2(p_size); - - if (size == reflection_atlas->size) - return; - if (reflection_atlas->size) { - for (int i = 0; i < 6; i++) { - glDeleteFramebuffers(1, &reflection_atlas->fbo[i]); - reflection_atlas->fbo[i] = 0; - } - glDeleteTextures(1, &reflection_atlas->color); - reflection_atlas->color = 0; - } - - reflection_atlas->size = size; - - for (int i = 0; i < reflection_atlas->reflections.size(); i++) { - //erase probes reference to this - if (reflection_atlas->reflections[i].owner.is_valid()) { - ReflectionProbeInstance *reflection_probe_instance = reflection_probe_instance_owner.getornull(reflection_atlas->reflections[i].owner); - reflection_atlas->reflections.write[i].owner = RID(); - - ERR_CONTINUE(!reflection_probe_instance); - reflection_probe_instance->reflection_atlas_index = -1; - reflection_probe_instance->atlas = RID(); - reflection_probe_instance->render_step = -1; - } - } - - if (reflection_atlas->size) { - - bool use_float = true; - - GLenum internal_format = use_float ? GL_RGBA16F : GL_RGB10_A2; - GLenum format = GL_RGBA; - GLenum type = use_float ? GL_HALF_FLOAT : GL_UNSIGNED_INT_2_10_10_10_REV; - - // Create a texture for storing the color - glActiveTexture(GL_TEXTURE0); - glGenTextures(1, &reflection_atlas->color); - glBindTexture(GL_TEXTURE_2D, reflection_atlas->color); - - int mmsize = reflection_atlas->size; - glTexStorage2DCustom(GL_TEXTURE_2D, 6, internal_format, mmsize, mmsize, format, type); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - 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_BASE_LEVEL, 0); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 5); - - for (int i = 0; i < 6; i++) { - glGenFramebuffers(1, &reflection_atlas->fbo[i]); - glBindFramebuffer(GL_FRAMEBUFFER, reflection_atlas->fbo[i]); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, reflection_atlas->color, i); - - GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); - ERR_CONTINUE(status != GL_FRAMEBUFFER_COMPLETE); - - glDisable(GL_SCISSOR_TEST); - glViewport(0, 0, mmsize, mmsize); - glClearColor(0, 0, 0, 0); - glClear(GL_COLOR_BUFFER_BIT); //it needs to be cleared, to avoid generating garbage - - mmsize >>= 1; - } - } -} - -void RasterizerSceneGLES3::reflection_atlas_set_subdivision(RID p_ref_atlas, int p_subdiv) { - - ReflectionAtlas *reflection_atlas = reflection_atlas_owner.getornull(p_ref_atlas); - ERR_FAIL_COND(!reflection_atlas); - - int subdiv = next_power_of_2(p_subdiv); - if (subdiv & 0xaaaaaaaa) { //sqrt(subdiv) must be integer - subdiv <<= 1; - } - - subdiv = int(Math::sqrt((float)subdiv)); - - if (reflection_atlas->subdiv == subdiv) - return; - - if (subdiv) { - - for (int i = 0; i < reflection_atlas->reflections.size(); i++) { - //erase probes reference to this - if (reflection_atlas->reflections[i].owner.is_valid()) { - ReflectionProbeInstance *reflection_probe_instance = reflection_probe_instance_owner.getornull(reflection_atlas->reflections[i].owner); - reflection_atlas->reflections.write[i].owner = RID(); - - ERR_CONTINUE(!reflection_probe_instance); - reflection_probe_instance->reflection_atlas_index = -1; - reflection_probe_instance->atlas = RID(); - reflection_probe_instance->render_step = -1; - } - } - } - - reflection_atlas->subdiv = subdiv; - - reflection_atlas->reflections.resize(subdiv * subdiv); -} - -//////////////////////////////////////////////////// - -RID RasterizerSceneGLES3::reflection_probe_instance_create(RID p_probe) { - - RasterizerStorageGLES3::ReflectionProbe *probe = storage->reflection_probe_owner.getornull(p_probe); - ERR_FAIL_COND_V(!probe, RID()); - - ReflectionProbeInstance *rpi = memnew(ReflectionProbeInstance); - - rpi->probe_ptr = probe; - rpi->self = reflection_probe_instance_owner.make_rid(rpi); - rpi->probe = p_probe; - rpi->reflection_atlas_index = -1; - rpi->render_step = -1; - rpi->last_pass = 0; - - return rpi->self; -} - -void RasterizerSceneGLES3::reflection_probe_instance_set_transform(RID p_instance, const Transform &p_transform) { - - ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance); - ERR_FAIL_COND(!rpi); - rpi->transform = p_transform; -} - -void RasterizerSceneGLES3::reflection_probe_release_atlas_index(RID p_instance) { - - ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance); - ERR_FAIL_COND(!rpi); - if (rpi->reflection_atlas_index == -1) - return; - - ReflectionAtlas *reflection_atlas = reflection_atlas_owner.getornull(rpi->atlas); - ERR_FAIL_COND(!reflection_atlas); - - ERR_FAIL_INDEX(rpi->reflection_atlas_index, reflection_atlas->reflections.size()); - - ERR_FAIL_COND(reflection_atlas->reflections[rpi->reflection_atlas_index].owner != rpi->self); - - reflection_atlas->reflections.write[rpi->reflection_atlas_index].owner = RID(); - - rpi->reflection_atlas_index = -1; - rpi->atlas = RID(); - rpi->render_step = -1; -} - -bool RasterizerSceneGLES3::reflection_probe_instance_needs_redraw(RID p_instance) { - - ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance); - ERR_FAIL_COND_V(!rpi, false); - - return rpi->reflection_atlas_index == -1 || rpi->probe_ptr->update_mode == VS::REFLECTION_PROBE_UPDATE_ALWAYS; -} - -bool RasterizerSceneGLES3::reflection_probe_instance_has_reflection(RID p_instance) { - - ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance); - ERR_FAIL_COND_V(!rpi, false); - - return rpi->reflection_atlas_index != -1; -} - -bool RasterizerSceneGLES3::reflection_probe_instance_begin_render(RID p_instance, RID p_reflection_atlas) { - - ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance); - ERR_FAIL_COND_V(!rpi, false); - - rpi->render_step = 0; - - if (rpi->reflection_atlas_index != -1) { - return true; //got one already - } - - ReflectionAtlas *reflection_atlas = reflection_atlas_owner.getornull(p_reflection_atlas); - ERR_FAIL_COND_V(!reflection_atlas, false); - - if (reflection_atlas->size == 0 || reflection_atlas->subdiv == 0) { - return false; - } - - int best_free = -1; - int best_used = -1; - uint64_t best_used_frame = 0; - - for (int i = 0; i < reflection_atlas->reflections.size(); i++) { - if (reflection_atlas->reflections[i].owner == RID()) { - best_free = i; - break; - } - - if (rpi->render_step < 0 && reflection_atlas->reflections[i].last_frame < storage->frame.count && - (best_used == -1 || reflection_atlas->reflections[i].last_frame < best_used_frame)) { - best_used = i; - best_used_frame = reflection_atlas->reflections[i].last_frame; - } - } - - if (best_free == -1 && best_used == -1) { - return false; // sorry, can not do. Try again next frame. - } - - if (best_free == -1) { - //find best from what is used - best_free = best_used; - - ReflectionProbeInstance *victim_rpi = reflection_probe_instance_owner.getornull(reflection_atlas->reflections[best_free].owner); - ERR_FAIL_COND_V(!victim_rpi, false); - victim_rpi->atlas = RID(); - victim_rpi->reflection_atlas_index = -1; - } - - reflection_atlas->reflections.write[best_free].owner = p_instance; - reflection_atlas->reflections.write[best_free].last_frame = storage->frame.count; - - rpi->reflection_atlas_index = best_free; - rpi->atlas = p_reflection_atlas; - rpi->render_step = 0; - - return true; -} - -bool RasterizerSceneGLES3::reflection_probe_instance_postprocess_step(RID p_instance) { - - ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance); - ERR_FAIL_COND_V(!rpi, true); - - ReflectionAtlas *reflection_atlas = reflection_atlas_owner.getornull(rpi->atlas); - ERR_FAIL_COND_V(!reflection_atlas, false); - - ERR_FAIL_COND_V(rpi->render_step >= 6, true); - - glBindFramebuffer(GL_FRAMEBUFFER, reflection_atlas->fbo[rpi->render_step]); - state.cube_to_dp_shader.bind(); - - int target_size = reflection_atlas->size / reflection_atlas->subdiv; - - int cubemap_index = reflection_cubemaps.size() - 1; - - for (int i = reflection_cubemaps.size() - 1; i >= 0; i--) { - //find appropriate cubemap to render to - if (reflection_cubemaps[i].size > target_size * 2) - break; - - cubemap_index = i; - } - - glDisable(GL_BLEND); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_CUBE_MAP, reflection_cubemaps[cubemap_index].cubemap); - glDisable(GL_CULL_FACE); - - storage->shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::USE_DUAL_PARABOLOID, true); - storage->shaders.cubemap_filter.bind(); - - int cell_size = reflection_atlas->size / reflection_atlas->subdiv; - for (int i = 0; i < rpi->render_step; i++) { - cell_size >>= 1; //mipmaps! - } - int x = (rpi->reflection_atlas_index % reflection_atlas->subdiv) * cell_size; - int y = (rpi->reflection_atlas_index / reflection_atlas->subdiv) * cell_size; - int width = cell_size; - int height = cell_size; - - storage->shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::USE_DIRECT_WRITE, rpi->render_step == 0); - storage->shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::LOW_QUALITY, rpi->probe_ptr->update_mode == VS::REFLECTION_PROBE_UPDATE_ALWAYS); - for (int i = 0; i < 2; i++) { - - storage->shaders.cubemap_filter.set_uniform(CubemapFilterShaderGLES3::Z_FLIP, i == 0); - storage->shaders.cubemap_filter.set_uniform(CubemapFilterShaderGLES3::ROUGHNESS, rpi->render_step / 5.0); - - uint32_t local_width = width, local_height = height; - uint32_t local_x = x, local_y = y; - - local_height /= 2; - local_y += i * local_height; - - glViewport(local_x, local_y, local_width, local_height); - - _copy_screen(); - } - storage->shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::USE_DIRECT_WRITE, false); - storage->shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::LOW_QUALITY, false); - - rpi->render_step++; - - return rpi->render_step == 6; -} - -/* ENVIRONMENT API */ - -RID RasterizerSceneGLES3::environment_create() { - - Environment *env = memnew(Environment); - - return environment_owner.make_rid(env); -} - -void RasterizerSceneGLES3::environment_set_background(RID p_env, VS::EnvironmentBG p_bg) { - - Environment *env = environment_owner.getornull(p_env); - ERR_FAIL_COND(!env); - env->bg_mode = p_bg; -} - -void RasterizerSceneGLES3::environment_set_sky(RID p_env, RID p_sky) { - - Environment *env = environment_owner.getornull(p_env); - ERR_FAIL_COND(!env); - - env->sky = p_sky; -} - -void RasterizerSceneGLES3::environment_set_sky_custom_fov(RID p_env, float p_scale) { - - Environment *env = environment_owner.getornull(p_env); - ERR_FAIL_COND(!env); - - env->sky_custom_fov = p_scale; -} - -void RasterizerSceneGLES3::environment_set_sky_orientation(RID p_env, const Basis &p_orientation) { - - Environment *env = environment_owner.getornull(p_env); - ERR_FAIL_COND(!env); - - env->sky_orientation = p_orientation; -} - -void RasterizerSceneGLES3::environment_set_bg_color(RID p_env, const Color &p_color) { - - Environment *env = environment_owner.getornull(p_env); - ERR_FAIL_COND(!env); - - env->bg_color = p_color; -} -void RasterizerSceneGLES3::environment_set_bg_energy(RID p_env, float p_energy) { - - Environment *env = environment_owner.getornull(p_env); - ERR_FAIL_COND(!env); - - env->bg_energy = p_energy; -} - -void RasterizerSceneGLES3::environment_set_canvas_max_layer(RID p_env, int p_max_layer) { - - Environment *env = environment_owner.getornull(p_env); - ERR_FAIL_COND(!env); - - env->canvas_max_layer = p_max_layer; -} -void RasterizerSceneGLES3::environment_set_ambient_light(RID p_env, const Color &p_color, float p_energy, float p_sky_contribution) { - - Environment *env = environment_owner.getornull(p_env); - ERR_FAIL_COND(!env); - - env->ambient_color = p_color; - env->ambient_energy = p_energy; - env->ambient_sky_contribution = p_sky_contribution; -} -void RasterizerSceneGLES3::environment_set_camera_feed_id(RID p_env, int p_camera_feed_id) { - Environment *env = environment_owner.getornull(p_env); - ERR_FAIL_COND(!env); - - env->camera_feed_id = p_camera_feed_id; -} - -void RasterizerSceneGLES3::environment_set_dof_blur_far(RID p_env, bool p_enable, float p_distance, float p_transition, float p_amount, VS::EnvironmentDOFBlurQuality p_quality) { - - Environment *env = environment_owner.getornull(p_env); - ERR_FAIL_COND(!env); - - env->dof_blur_far_enabled = p_enable; - env->dof_blur_far_distance = p_distance; - env->dof_blur_far_transition = p_transition; - env->dof_blur_far_amount = p_amount; - env->dof_blur_far_quality = p_quality; -} - -void RasterizerSceneGLES3::environment_set_dof_blur_near(RID p_env, bool p_enable, float p_distance, float p_transition, float p_amount, VS::EnvironmentDOFBlurQuality p_quality) { - - Environment *env = environment_owner.getornull(p_env); - ERR_FAIL_COND(!env); - - env->dof_blur_near_enabled = p_enable; - env->dof_blur_near_distance = p_distance; - env->dof_blur_near_transition = p_transition; - env->dof_blur_near_amount = p_amount; - env->dof_blur_near_quality = p_quality; -} -void RasterizerSceneGLES3::environment_set_glow(RID p_env, bool p_enable, int p_level_flags, float p_intensity, float p_strength, float p_bloom_threshold, VS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap, bool p_bicubic_upscale) { - - Environment *env = environment_owner.getornull(p_env); - ERR_FAIL_COND(!env); - - env->glow_enabled = p_enable; - env->glow_levels = p_level_flags; - env->glow_intensity = p_intensity; - env->glow_strength = p_strength; - env->glow_bloom = p_bloom_threshold; - env->glow_blend_mode = p_blend_mode; - env->glow_hdr_bleed_threshold = p_hdr_bleed_threshold; - env->glow_hdr_bleed_scale = p_hdr_bleed_scale; - env->glow_hdr_luminance_cap = p_hdr_luminance_cap; - env->glow_bicubic_upscale = p_bicubic_upscale; -} -void RasterizerSceneGLES3::environment_set_fog(RID p_env, bool p_enable, float p_begin, float p_end, RID p_gradient_texture) { -} - -void RasterizerSceneGLES3::environment_set_ssr(RID p_env, bool p_enable, int p_max_steps, float p_fade_in, float p_fade_out, float p_depth_tolerance, bool p_roughness) { - - Environment *env = environment_owner.getornull(p_env); - ERR_FAIL_COND(!env); - - env->ssr_enabled = p_enable; - env->ssr_max_steps = p_max_steps; - env->ssr_fade_in = p_fade_in; - env->ssr_fade_out = p_fade_out; - env->ssr_depth_tolerance = p_depth_tolerance; - env->ssr_roughness = p_roughness; -} - -void RasterizerSceneGLES3::environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_radius2, float p_intensity2, float p_bias, float p_light_affect, float p_ao_channel_affect, const Color &p_color, VS::EnvironmentSSAOQuality p_quality, VisualServer::EnvironmentSSAOBlur p_blur, float p_bilateral_sharpness) { - - Environment *env = environment_owner.getornull(p_env); - ERR_FAIL_COND(!env); - - env->ssao_enabled = p_enable; - env->ssao_radius = p_radius; - env->ssao_intensity = p_intensity; - env->ssao_radius2 = p_radius2; - env->ssao_intensity2 = p_intensity2; - env->ssao_bias = p_bias; - env->ssao_light_affect = p_light_affect; - env->ssao_ao_channel_affect = p_ao_channel_affect; - env->ssao_color = p_color; - env->ssao_filter = p_blur; - env->ssao_quality = p_quality; - env->ssao_bilateral_sharpness = p_bilateral_sharpness; -} - -void RasterizerSceneGLES3::environment_set_tonemap(RID p_env, VS::EnvironmentToneMapper p_tone_mapper, float p_exposure, float p_white, bool p_auto_exposure, float p_min_luminance, float p_max_luminance, float p_auto_exp_speed, float p_auto_exp_scale) { - - Environment *env = environment_owner.getornull(p_env); - ERR_FAIL_COND(!env); - - env->tone_mapper = p_tone_mapper; - env->tone_mapper_exposure = p_exposure; - env->tone_mapper_exposure_white = p_white; - env->auto_exposure = p_auto_exposure; - env->auto_exposure_speed = p_auto_exp_speed; - env->auto_exposure_min = p_min_luminance; - env->auto_exposure_max = p_max_luminance; - env->auto_exposure_grey = p_auto_exp_scale; -} - -void RasterizerSceneGLES3::environment_set_adjustment(RID p_env, bool p_enable, float p_brightness, float p_contrast, float p_saturation, RID p_ramp) { - - Environment *env = environment_owner.getornull(p_env); - ERR_FAIL_COND(!env); - - env->adjustments_enabled = p_enable; - env->adjustments_brightness = p_brightness; - env->adjustments_contrast = p_contrast; - env->adjustments_saturation = p_saturation; - env->color_correction = p_ramp; -} - -void RasterizerSceneGLES3::environment_set_fog(RID p_env, bool p_enable, const Color &p_color, const Color &p_sun_color, float p_sun_amount) { - - Environment *env = environment_owner.getornull(p_env); - ERR_FAIL_COND(!env); - - env->fog_enabled = p_enable; - env->fog_color = p_color; - env->fog_sun_color = p_sun_color; - env->fog_sun_amount = p_sun_amount; -} - -void RasterizerSceneGLES3::environment_set_fog_depth(RID p_env, bool p_enable, float p_depth_begin, float p_depth_end, float p_depth_curve, bool p_transmit, float p_transmit_curve) { - - Environment *env = environment_owner.getornull(p_env); - ERR_FAIL_COND(!env); - - env->fog_depth_enabled = p_enable; - env->fog_depth_begin = p_depth_begin; - env->fog_depth_end = p_depth_end; - env->fog_depth_curve = p_depth_curve; - env->fog_transmit_enabled = p_transmit; - env->fog_transmit_curve = p_transmit_curve; -} - -void RasterizerSceneGLES3::environment_set_fog_height(RID p_env, bool p_enable, float p_min_height, float p_max_height, float p_height_curve) { - - Environment *env = environment_owner.getornull(p_env); - ERR_FAIL_COND(!env); - - env->fog_height_enabled = p_enable; - env->fog_height_min = p_min_height; - env->fog_height_max = p_max_height; - env->fog_height_curve = p_height_curve; -} - -bool RasterizerSceneGLES3::is_environment(RID p_env) { - - return environment_owner.owns(p_env); -} - -VS::EnvironmentBG RasterizerSceneGLES3::environment_get_background(RID p_env) { - - const Environment *env = environment_owner.getornull(p_env); - ERR_FAIL_COND_V(!env, VS::ENV_BG_MAX); - - return env->bg_mode; -} - -int RasterizerSceneGLES3::environment_get_canvas_max_layer(RID p_env) { - - const Environment *env = environment_owner.getornull(p_env); - ERR_FAIL_COND_V(!env, -1); - - return env->canvas_max_layer; -} - -RID RasterizerSceneGLES3::light_instance_create(RID p_light) { - - LightInstance *light_instance = memnew(LightInstance); - - light_instance->last_pass = 0; - light_instance->last_scene_pass = 0; - light_instance->last_scene_shadow_pass = 0; - - light_instance->light = p_light; - light_instance->light_ptr = storage->light_owner.getornull(p_light); - - if (!light_instance->light_ptr) { - memdelete(light_instance); - ERR_FAIL_V_MSG(RID(), "Condition ' !light_instance->light_ptr ' is true."); - } - - light_instance->self = light_instance_owner.make_rid(light_instance); - - return light_instance->self; -} - -void RasterizerSceneGLES3::light_instance_set_transform(RID p_light_instance, const Transform &p_transform) { - - LightInstance *light_instance = light_instance_owner.getornull(p_light_instance); - ERR_FAIL_COND(!light_instance); - - light_instance->transform = p_transform; -} - -void RasterizerSceneGLES3::light_instance_set_shadow_transform(RID p_light_instance, const CameraMatrix &p_projection, const Transform &p_transform, float p_far, float p_split, int p_pass, float p_bias_scale) { - - LightInstance *light_instance = light_instance_owner.getornull(p_light_instance); - ERR_FAIL_COND(!light_instance); - - if (light_instance->light_ptr->type != VS::LIGHT_DIRECTIONAL) { - p_pass = 0; - } - - ERR_FAIL_INDEX(p_pass, 4); - - light_instance->shadow_transform[p_pass].camera = p_projection; - light_instance->shadow_transform[p_pass].transform = p_transform; - light_instance->shadow_transform[p_pass].farplane = p_far; - light_instance->shadow_transform[p_pass].split = p_split; - light_instance->shadow_transform[p_pass].bias_scale = p_bias_scale; -} - -void RasterizerSceneGLES3::light_instance_mark_visible(RID p_light_instance) { - - LightInstance *light_instance = light_instance_owner.getornull(p_light_instance); - ERR_FAIL_COND(!light_instance); - - light_instance->last_scene_pass = scene_pass; -} - -////////////////////// - -RID RasterizerSceneGLES3::gi_probe_instance_create() { - - GIProbeInstance *gipi = memnew(GIProbeInstance); - - return gi_probe_instance_owner.make_rid(gipi); -} - -void RasterizerSceneGLES3::gi_probe_instance_set_light_data(RID p_probe, RID p_base, RID p_data) { - - GIProbeInstance *gipi = gi_probe_instance_owner.getornull(p_probe); - ERR_FAIL_COND(!gipi); - gipi->data = p_data; - gipi->probe = storage->gi_probe_owner.getornull(p_base); - if (p_data.is_valid()) { - RasterizerStorageGLES3::GIProbeData *gipd = storage->gi_probe_data_owner.getornull(p_data); - ERR_FAIL_COND(!gipd); - - gipi->tex_cache = gipd->tex_id; - gipi->cell_size_cache.x = 1.0 / gipd->width; - gipi->cell_size_cache.y = 1.0 / gipd->height; - gipi->cell_size_cache.z = 1.0 / gipd->depth; - } -} -void RasterizerSceneGLES3::gi_probe_instance_set_transform_to_data(RID p_probe, const Transform &p_xform) { - - GIProbeInstance *gipi = gi_probe_instance_owner.getornull(p_probe); - ERR_FAIL_COND(!gipi); - gipi->transform_to_data = p_xform; -} - -void RasterizerSceneGLES3::gi_probe_instance_set_bounds(RID p_probe, const Vector3 &p_bounds) { - - GIProbeInstance *gipi = gi_probe_instance_owner.getornull(p_probe); - ERR_FAIL_COND(!gipi); - gipi->bounds = p_bounds; -} - -//////////////////////////// -//////////////////////////// -//////////////////////////// - -bool RasterizerSceneGLES3::_setup_material(RasterizerStorageGLES3::Material *p_material, bool p_depth_pass, bool p_alpha_pass) { - - /* this is handled outside - if (p_material->shader->spatial.cull_mode == RasterizerStorageGLES3::Shader::Spatial::CULL_MODE_DISABLED) { - glDisable(GL_CULL_FACE); - } else { - glEnable(GL_CULL_FACE); - } */ - - if (state.current_line_width != p_material->line_width) { - //glLineWidth(MAX(p_material->line_width,1.0)); - state.current_line_width = p_material->line_width; - } - - if (state.current_depth_test != (!p_material->shader->spatial.no_depth_test)) { - if (p_material->shader->spatial.no_depth_test) { - glDisable(GL_DEPTH_TEST); - - } else { - glEnable(GL_DEPTH_TEST); - } - - state.current_depth_test = !p_material->shader->spatial.no_depth_test; - } - - if (state.current_depth_draw != p_material->shader->spatial.depth_draw_mode) { - switch (p_material->shader->spatial.depth_draw_mode) { - case RasterizerStorageGLES3::Shader::Spatial::DEPTH_DRAW_ALPHA_PREPASS: { - glDepthMask(p_depth_pass); - // If some transparent objects write to depth, we need to re-copy depth texture when we need it - if (p_alpha_pass && !state.used_depth_prepass) { - state.prepared_depth_texture = false; - } - } break; - case RasterizerStorageGLES3::Shader::Spatial::DEPTH_DRAW_OPAQUE: { - - glDepthMask(!p_alpha_pass); - } break; - case RasterizerStorageGLES3::Shader::Spatial::DEPTH_DRAW_ALWAYS: { - glDepthMask(GL_TRUE); - // If some transparent objects write to depth, we need to re-copy depth texture when we need it - if (p_alpha_pass) { - state.prepared_depth_texture = false; - } - } break; - case RasterizerStorageGLES3::Shader::Spatial::DEPTH_DRAW_NEVER: { - glDepthMask(GL_FALSE); - } break; - } - - state.current_depth_draw = p_material->shader->spatial.depth_draw_mode; - } - - //material parameters - - state.scene_shader.set_custom_shader(p_material->shader->custom_code_id); - bool rebind = state.scene_shader.bind(); - - if (p_material->ubo_id) { - - glBindBufferBase(GL_UNIFORM_BUFFER, 1, p_material->ubo_id); - } - - int tc = p_material->textures.size(); - RID *textures = p_material->textures.ptrw(); - ShaderLanguage::ShaderNode::Uniform::Hint *texture_hints = p_material->shader->texture_hints.ptrw(); - const ShaderLanguage::DataType *texture_types = p_material->shader->texture_types.ptr(); - - state.current_main_tex = 0; - - for (int i = 0; i < tc; i++) { - - glActiveTexture(GL_TEXTURE0 + i); - - GLenum target = GL_TEXTURE_2D; - GLuint tex = 0; - - RasterizerStorageGLES3::Texture *t = storage->texture_owner.getptr(textures[i]); - - if (t) { - - if (t->redraw_if_visible) { //must check before proxy because this is often used with proxies - VisualServerRaster::redraw_request(); - } - - t = t->get_ptr(); //resolve for proxies - -#ifdef TOOLS_ENABLED - if (t->detect_3d) { - t->detect_3d(t->detect_3d_ud); - } -#endif - -#ifdef TOOLS_ENABLED - if (t->detect_normal && texture_hints[i] == ShaderLanguage::ShaderNode::Uniform::HINT_NORMAL) { - t->detect_normal(t->detect_normal_ud); - } -#endif - if (t->render_target) - t->render_target->used_in_frame = true; - - target = t->target; - tex = t->tex_id; - } else { - - switch (texture_types[i]) { - case ShaderLanguage::TYPE_ISAMPLER2D: - case ShaderLanguage::TYPE_USAMPLER2D: - case ShaderLanguage::TYPE_SAMPLER2D: { - target = GL_TEXTURE_2D; - - switch (texture_hints[i]) { - case ShaderLanguage::ShaderNode::Uniform::HINT_BLACK_ALBEDO: - case ShaderLanguage::ShaderNode::Uniform::HINT_BLACK: { - tex = storage->resources.black_tex; - } break; - case ShaderLanguage::ShaderNode::Uniform::HINT_ANISO: { - tex = storage->resources.aniso_tex; - } break; - case ShaderLanguage::ShaderNode::Uniform::HINT_NORMAL: { - tex = storage->resources.normal_tex; - - } break; - default: { - tex = storage->resources.white_tex; - } break; - } - - } break; - - case ShaderLanguage::TYPE_SAMPLERCUBE: { - // TODO - } break; - - case ShaderLanguage::TYPE_ISAMPLER3D: - case ShaderLanguage::TYPE_USAMPLER3D: - case ShaderLanguage::TYPE_SAMPLER3D: { - - target = GL_TEXTURE_3D; - tex = storage->resources.white_tex_3d; - - //switch (texture_hints[i]) { - // TODO - //} - - } break; - - case ShaderLanguage::TYPE_ISAMPLER2DARRAY: - case ShaderLanguage::TYPE_USAMPLER2DARRAY: - case ShaderLanguage::TYPE_SAMPLER2DARRAY: { - - target = GL_TEXTURE_2D_ARRAY; - tex = storage->resources.white_tex_array; - - //switch (texture_hints[i]) { - // TODO - //} - - } break; - - default: { - } - } - } - - glBindTexture(target, tex); - - if (t && storage->config.srgb_decode_supported) { - //if SRGB decode extension is present, simply switch the texture to whathever is needed - bool must_srgb = false; - - if (t->srgb && (texture_hints[i] == ShaderLanguage::ShaderNode::Uniform::HINT_ALBEDO || texture_hints[i] == ShaderLanguage::ShaderNode::Uniform::HINT_BLACK_ALBEDO)) { - must_srgb = true; - } - - if (t->using_srgb != must_srgb) { - if (must_srgb) { - glTexParameteri(t->target, _TEXTURE_SRGB_DECODE_EXT, _DECODE_EXT); -#ifdef TOOLS_ENABLED - if (t->detect_srgb) { - t->detect_srgb(t->detect_srgb_ud); - } -#endif - - } else { - glTexParameteri(t->target, _TEXTURE_SRGB_DECODE_EXT, _SKIP_DECODE_EXT); - } - t->using_srgb = must_srgb; - } - } - - if (i == 0) { - state.current_main_tex = tex; - } - } - - return rebind; -} - -struct RasterizerGLES3Particle { - - float color[4]; - float velocity_active[4]; - float custom[4]; - float xform_1[4]; - float xform_2[4]; - float xform_3[4]; -}; - -struct RasterizerGLES3ParticleSort { - - Vector3 z_dir; - bool operator()(const RasterizerGLES3Particle &p_a, const RasterizerGLES3Particle &p_b) const { - - return z_dir.dot(Vector3(p_a.xform_1[3], p_a.xform_2[3], p_a.xform_3[3])) < z_dir.dot(Vector3(p_b.xform_1[3], p_b.xform_2[3], p_b.xform_3[3])); - } -}; - -void RasterizerSceneGLES3::_setup_geometry(RenderList::Element *e, const Transform &p_view_transform) { - - switch (e->instance->base_type) { - - case VS::INSTANCE_MESH: { - - RasterizerStorageGLES3::Surface *s = static_cast<RasterizerStorageGLES3::Surface *>(e->geometry); - - if (s->blend_shapes.size() && e->instance->blend_values.size()) { - //blend shapes, use transform feedback - storage->mesh_render_blend_shapes(s, e->instance->blend_values.ptr()); - //rebind shader - state.scene_shader.bind(); -#ifdef DEBUG_ENABLED - } else if (state.debug_draw == VS::VIEWPORT_DEBUG_DRAW_WIREFRAME && s->array_wireframe_id) { - glBindVertexArray(s->array_wireframe_id); // everything is so easy nowadays -#endif - } else { - glBindVertexArray(s->array_id); // everything is so easy nowadays - } - - } break; - - case VS::INSTANCE_MULTIMESH: { - - RasterizerStorageGLES3::MultiMesh *multi_mesh = static_cast<RasterizerStorageGLES3::MultiMesh *>(e->owner); - RasterizerStorageGLES3::Surface *s = static_cast<RasterizerStorageGLES3::Surface *>(e->geometry); -#ifdef DEBUG_ENABLED - if (state.debug_draw == VS::VIEWPORT_DEBUG_DRAW_WIREFRAME && s->instancing_array_wireframe_id) { - - glBindVertexArray(s->instancing_array_wireframe_id); // use the instancing array ID - } else -#endif - { - glBindVertexArray(s->instancing_array_id); // use the instancing array ID - } - - glBindBuffer(GL_ARRAY_BUFFER, multi_mesh->buffer); //modify the buffer - - int stride = (multi_mesh->xform_floats + multi_mesh->color_floats + multi_mesh->custom_data_floats) * 4; - glEnableVertexAttribArray(8); - glVertexAttribPointer(8, 4, GL_FLOAT, GL_FALSE, stride, NULL); - glVertexAttribDivisor(8, 1); - glEnableVertexAttribArray(9); - glVertexAttribPointer(9, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(4 * 4)); - glVertexAttribDivisor(9, 1); - - int color_ofs; - - if (multi_mesh->transform_format == VS::MULTIMESH_TRANSFORM_3D) { - glEnableVertexAttribArray(10); - glVertexAttribPointer(10, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(8 * 4)); - glVertexAttribDivisor(10, 1); - color_ofs = 12 * 4; - } else { - glDisableVertexAttribArray(10); - glVertexAttrib4f(10, 0, 0, 1, 0); - color_ofs = 8 * 4; - } - - int custom_data_ofs = color_ofs; - - switch (multi_mesh->color_format) { - - case VS::MULTIMESH_COLOR_MAX: - case VS::MULTIMESH_COLOR_NONE: { - glDisableVertexAttribArray(11); - glVertexAttrib4f(11, 1, 1, 1, 1); - } break; - case VS::MULTIMESH_COLOR_8BIT: { - glEnableVertexAttribArray(11); - glVertexAttribPointer(11, 4, GL_UNSIGNED_BYTE, GL_TRUE, stride, CAST_INT_TO_UCHAR_PTR(color_ofs)); - glVertexAttribDivisor(11, 1); - custom_data_ofs += 4; - - } break; - case VS::MULTIMESH_COLOR_FLOAT: { - glEnableVertexAttribArray(11); - glVertexAttribPointer(11, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(color_ofs)); - glVertexAttribDivisor(11, 1); - custom_data_ofs += 4 * 4; - } break; - } - - switch (multi_mesh->custom_data_format) { - - case VS::MULTIMESH_CUSTOM_DATA_MAX: - case VS::MULTIMESH_CUSTOM_DATA_NONE: { - glDisableVertexAttribArray(12); - glVertexAttrib4f(12, 1, 1, 1, 1); - } break; - case VS::MULTIMESH_CUSTOM_DATA_8BIT: { - glEnableVertexAttribArray(12); - glVertexAttribPointer(12, 4, GL_UNSIGNED_BYTE, GL_TRUE, stride, CAST_INT_TO_UCHAR_PTR(custom_data_ofs)); - glVertexAttribDivisor(12, 1); - - } break; - case VS::MULTIMESH_CUSTOM_DATA_FLOAT: { - glEnableVertexAttribArray(12); - glVertexAttribPointer(12, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(custom_data_ofs)); - glVertexAttribDivisor(12, 1); - } break; - } - - } break; - case VS::INSTANCE_PARTICLES: { - - RasterizerStorageGLES3::Particles *particles = static_cast<RasterizerStorageGLES3::Particles *>(e->owner); - RasterizerStorageGLES3::Surface *s = static_cast<RasterizerStorageGLES3::Surface *>(e->geometry); - - if (particles->draw_order == VS::PARTICLES_DRAW_ORDER_VIEW_DEPTH && particles->particle_valid_histories[1]) { - - glBindBuffer(GL_ARRAY_BUFFER, particles->particle_buffer_histories[1]); //modify the buffer, this was used 2 frames ago so it should be good enough for flushing - RasterizerGLES3Particle *particle_array; -#ifndef __EMSCRIPTEN__ - particle_array = static_cast<RasterizerGLES3Particle *>(glMapBufferRange(GL_ARRAY_BUFFER, 0, particles->amount * 24 * sizeof(float), GL_MAP_READ_BIT | GL_MAP_WRITE_BIT)); -#else - PoolVector<RasterizerGLES3Particle> particle_vector; - particle_vector.resize(particles->amount); - PoolVector<RasterizerGLES3Particle>::Write particle_writer = particle_vector.write(); - particle_array = particle_writer.ptr(); - glGetBufferSubData(GL_ARRAY_BUFFER, 0, particles->amount * sizeof(RasterizerGLES3Particle), particle_array); -#endif - - SortArray<RasterizerGLES3Particle, RasterizerGLES3ParticleSort> sorter; - - if (particles->use_local_coords) { - sorter.compare.z_dir = e->instance->transform.affine_inverse().xform(p_view_transform.basis.get_axis(2)).normalized(); - } else { - sorter.compare.z_dir = p_view_transform.basis.get_axis(2).normalized(); - } - - sorter.sort(particle_array, particles->amount); - -#ifndef __EMSCRIPTEN__ - glUnmapBuffer(GL_ARRAY_BUFFER); -#else - particle_writer.release(); - particle_array = NULL; - { - PoolVector<RasterizerGLES3Particle>::Read r = particle_vector.read(); - glBufferSubData(GL_ARRAY_BUFFER, 0, particles->amount * sizeof(RasterizerGLES3Particle), r.ptr()); - } - particle_vector = PoolVector<RasterizerGLES3Particle>(); -#endif -#ifdef DEBUG_ENABLED - if (state.debug_draw == VS::VIEWPORT_DEBUG_DRAW_WIREFRAME && s->instancing_array_wireframe_id) { - glBindVertexArray(s->instancing_array_wireframe_id); // use the wireframe instancing array ID - } else -#endif - { - - glBindVertexArray(s->instancing_array_id); // use the instancing array ID - } - glBindBuffer(GL_ARRAY_BUFFER, particles->particle_buffer_histories[1]); //modify the buffer - - } else { -#ifdef DEBUG_ENABLED - if (state.debug_draw == VS::VIEWPORT_DEBUG_DRAW_WIREFRAME && s->instancing_array_wireframe_id) { - glBindVertexArray(s->instancing_array_wireframe_id); // use the wireframe instancing array ID - } else -#endif - { - glBindVertexArray(s->instancing_array_id); // use the instancing array ID - } - glBindBuffer(GL_ARRAY_BUFFER, particles->particle_buffers[0]); //modify the buffer - } - - int stride = sizeof(float) * 4 * 6; - - //transform - - if (particles->draw_order != VS::PARTICLES_DRAW_ORDER_LIFETIME) { - - glEnableVertexAttribArray(8); //xform x - glVertexAttribPointer(8, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(sizeof(float) * 4 * 3)); - glVertexAttribDivisor(8, 1); - glEnableVertexAttribArray(9); //xform y - glVertexAttribPointer(9, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(sizeof(float) * 4 * 4)); - glVertexAttribDivisor(9, 1); - glEnableVertexAttribArray(10); //xform z - glVertexAttribPointer(10, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(sizeof(float) * 4 * 5)); - glVertexAttribDivisor(10, 1); - glEnableVertexAttribArray(11); //color - glVertexAttribPointer(11, 4, GL_FLOAT, GL_FALSE, stride, NULL); - glVertexAttribDivisor(11, 1); - glEnableVertexAttribArray(12); //custom - glVertexAttribPointer(12, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(sizeof(float) * 4 * 2)); - glVertexAttribDivisor(12, 1); - } - - } break; - default: { - } - } -} - -static const GLenum gl_primitive[] = { - GL_POINTS, - GL_LINES, - GL_LINE_STRIP, - GL_LINE_LOOP, - GL_TRIANGLES, - GL_TRIANGLE_STRIP, - GL_TRIANGLE_FAN -}; - -void RasterizerSceneGLES3::_render_geometry(RenderList::Element *e) { - - switch (e->instance->base_type) { - - case VS::INSTANCE_MESH: { - - RasterizerStorageGLES3::Surface *s = static_cast<RasterizerStorageGLES3::Surface *>(e->geometry); - -#ifdef DEBUG_ENABLED - - if (state.debug_draw == VS::VIEWPORT_DEBUG_DRAW_WIREFRAME && s->array_wireframe_id) { - - glDrawElements(GL_LINES, s->index_wireframe_len, GL_UNSIGNED_INT, 0); - storage->info.render.vertices_count += s->index_array_len; - } else -#endif - if (s->index_array_len > 0) { - - glDrawElements(gl_primitive[s->primitive], s->index_array_len, (s->array_len >= (1 << 16)) ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT, 0); - - storage->info.render.vertices_count += s->index_array_len; - - } else { - - glDrawArrays(gl_primitive[s->primitive], 0, s->array_len); - - storage->info.render.vertices_count += s->array_len; - } - - } break; - case VS::INSTANCE_MULTIMESH: { - - RasterizerStorageGLES3::MultiMesh *multi_mesh = static_cast<RasterizerStorageGLES3::MultiMesh *>(e->owner); - RasterizerStorageGLES3::Surface *s = static_cast<RasterizerStorageGLES3::Surface *>(e->geometry); - - int amount = MIN(multi_mesh->size, multi_mesh->visible_instances); - - if (amount == -1) { - amount = multi_mesh->size; - } -#ifdef DEBUG_ENABLED - - if (state.debug_draw == VS::VIEWPORT_DEBUG_DRAW_WIREFRAME && s->array_wireframe_id) { - - glDrawElementsInstanced(GL_LINES, s->index_wireframe_len, GL_UNSIGNED_INT, 0, amount); - storage->info.render.vertices_count += s->index_array_len * amount; - } else -#endif - if (s->index_array_len > 0) { - - glDrawElementsInstanced(gl_primitive[s->primitive], s->index_array_len, (s->array_len >= (1 << 16)) ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT, 0, amount); - - storage->info.render.vertices_count += s->index_array_len * amount; - - } else { - - glDrawArraysInstanced(gl_primitive[s->primitive], 0, s->array_len, amount); - - storage->info.render.vertices_count += s->array_len * amount; - } - - } break; - case VS::INSTANCE_IMMEDIATE: { - - bool restore_tex = false; - const RasterizerStorageGLES3::Immediate *im = static_cast<const RasterizerStorageGLES3::Immediate *>(e->geometry); - - if (im->building) { - return; - } - - glBindBuffer(GL_ARRAY_BUFFER, state.immediate_buffer); - glBindVertexArray(state.immediate_array); - - for (const List<RasterizerStorageGLES3::Immediate::Chunk>::Element *E = im->chunks.front(); E; E = E->next()) { - - const RasterizerStorageGLES3::Immediate::Chunk &c = E->get(); - if (c.vertices.empty()) { - continue; - } - - int vertices = c.vertices.size(); - uint32_t buf_ofs = 0; - - storage->info.render.vertices_count += vertices; - - if (c.texture.is_valid() && storage->texture_owner.owns(c.texture)) { - - RasterizerStorageGLES3::Texture *t = storage->texture_owner.get(c.texture); - - if (t->redraw_if_visible) { - VisualServerRaster::redraw_request(); - } - t = t->get_ptr(); //resolve for proxies - -#ifdef TOOLS_ENABLED - if (t->detect_3d) { - t->detect_3d(t->detect_3d_ud); - } -#endif - - if (t->render_target) { - t->render_target->used_in_frame = true; - } - - glActiveTexture(GL_TEXTURE0); - glBindTexture(t->target, t->tex_id); - restore_tex = true; - - } else if (restore_tex) { - - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, state.current_main_tex); - restore_tex = false; - } - - if (!c.normals.empty()) { - - glEnableVertexAttribArray(VS::ARRAY_NORMAL); - glBufferSubData(GL_ARRAY_BUFFER, buf_ofs, sizeof(Vector3) * vertices, c.normals.ptr()); - glVertexAttribPointer(VS::ARRAY_NORMAL, 3, GL_FLOAT, false, sizeof(Vector3), CAST_INT_TO_UCHAR_PTR(buf_ofs)); - buf_ofs += sizeof(Vector3) * vertices; - - } else { - - glDisableVertexAttribArray(VS::ARRAY_NORMAL); - } - - if (!c.tangents.empty()) { - - glEnableVertexAttribArray(VS::ARRAY_TANGENT); - glBufferSubData(GL_ARRAY_BUFFER, buf_ofs, sizeof(Plane) * vertices, c.tangents.ptr()); - glVertexAttribPointer(VS::ARRAY_TANGENT, 4, GL_FLOAT, false, sizeof(Plane), CAST_INT_TO_UCHAR_PTR(buf_ofs)); - buf_ofs += sizeof(Plane) * vertices; - - } else { - - glDisableVertexAttribArray(VS::ARRAY_TANGENT); - } - - if (!c.colors.empty()) { - - glEnableVertexAttribArray(VS::ARRAY_COLOR); - glBufferSubData(GL_ARRAY_BUFFER, buf_ofs, sizeof(Color) * vertices, c.colors.ptr()); - glVertexAttribPointer(VS::ARRAY_COLOR, 4, GL_FLOAT, false, sizeof(Color), CAST_INT_TO_UCHAR_PTR(buf_ofs)); - buf_ofs += sizeof(Color) * vertices; - - } else { - - glDisableVertexAttribArray(VS::ARRAY_COLOR); - glVertexAttrib4f(VS::ARRAY_COLOR, 1, 1, 1, 1); - } - - if (!c.uvs.empty()) { - - glEnableVertexAttribArray(VS::ARRAY_TEX_UV); - glBufferSubData(GL_ARRAY_BUFFER, buf_ofs, sizeof(Vector2) * vertices, c.uvs.ptr()); - glVertexAttribPointer(VS::ARRAY_TEX_UV, 2, GL_FLOAT, false, sizeof(Vector2), CAST_INT_TO_UCHAR_PTR(buf_ofs)); - buf_ofs += sizeof(Vector2) * vertices; - - } else { - - glDisableVertexAttribArray(VS::ARRAY_TEX_UV); - } - - if (!c.uvs2.empty()) { - - glEnableVertexAttribArray(VS::ARRAY_TEX_UV2); - glBufferSubData(GL_ARRAY_BUFFER, buf_ofs, sizeof(Vector2) * vertices, c.uvs2.ptr()); - glVertexAttribPointer(VS::ARRAY_TEX_UV2, 2, GL_FLOAT, false, sizeof(Vector2), CAST_INT_TO_UCHAR_PTR(buf_ofs)); - buf_ofs += sizeof(Vector2) * vertices; - - } else { - - glDisableVertexAttribArray(VS::ARRAY_TEX_UV2); - } - - glEnableVertexAttribArray(VS::ARRAY_VERTEX); - glBufferSubData(GL_ARRAY_BUFFER, buf_ofs, sizeof(Vector3) * vertices, c.vertices.ptr()); - glVertexAttribPointer(VS::ARRAY_VERTEX, 3, GL_FLOAT, false, sizeof(Vector3), CAST_INT_TO_UCHAR_PTR(buf_ofs)); - glDrawArrays(gl_primitive[c.primitive], 0, c.vertices.size()); - } - - if (restore_tex) { - - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, state.current_main_tex); - restore_tex = false; - } - } break; - case VS::INSTANCE_PARTICLES: { - - RasterizerStorageGLES3::Particles *particles = static_cast<RasterizerStorageGLES3::Particles *>(e->owner); - RasterizerStorageGLES3::Surface *s = static_cast<RasterizerStorageGLES3::Surface *>(e->geometry); - - if (!particles->use_local_coords) //not using local coordinates? then clear transform.. - state.scene_shader.set_uniform(SceneShaderGLES3::WORLD_TRANSFORM, Transform()); - - int amount = particles->amount; - - if (particles->draw_order == VS::PARTICLES_DRAW_ORDER_LIFETIME) { - //split - - int stride = sizeof(float) * 4 * 6; - int split = int(Math::ceil(particles->phase * particles->amount)); - - if (amount - split > 0) { - glEnableVertexAttribArray(8); //xform x - glVertexAttribPointer(8, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(stride * split + sizeof(float) * 4 * 3)); - glVertexAttribDivisor(8, 1); - glEnableVertexAttribArray(9); //xform y - glVertexAttribPointer(9, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(stride * split + sizeof(float) * 4 * 4)); - glVertexAttribDivisor(9, 1); - glEnableVertexAttribArray(10); //xform z - glVertexAttribPointer(10, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(stride * split + sizeof(float) * 4 * 5)); - glVertexAttribDivisor(10, 1); - glEnableVertexAttribArray(11); //color - glVertexAttribPointer(11, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(stride * split + 0)); - glVertexAttribDivisor(11, 1); - glEnableVertexAttribArray(12); //custom - glVertexAttribPointer(12, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(stride * split + sizeof(float) * 4 * 2)); - glVertexAttribDivisor(12, 1); -#ifdef DEBUG_ENABLED - - if (state.debug_draw == VS::VIEWPORT_DEBUG_DRAW_WIREFRAME && s->array_wireframe_id) { - - glDrawElementsInstanced(GL_LINES, s->index_wireframe_len, GL_UNSIGNED_INT, 0, amount - split); - storage->info.render.vertices_count += s->index_array_len * (amount - split); - } else -#endif - if (s->index_array_len > 0) { - - glDrawElementsInstanced(gl_primitive[s->primitive], s->index_array_len, (s->array_len >= (1 << 16)) ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT, 0, amount - split); - - storage->info.render.vertices_count += s->index_array_len * (amount - split); - - } else { - - glDrawArraysInstanced(gl_primitive[s->primitive], 0, s->array_len, amount - split); - - storage->info.render.vertices_count += s->array_len * (amount - split); - } - } - - if (split > 0) { - glEnableVertexAttribArray(8); //xform x - glVertexAttribPointer(8, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(sizeof(float) * 4 * 3)); - glVertexAttribDivisor(8, 1); - glEnableVertexAttribArray(9); //xform y - glVertexAttribPointer(9, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(sizeof(float) * 4 * 4)); - glVertexAttribDivisor(9, 1); - glEnableVertexAttribArray(10); //xform z - glVertexAttribPointer(10, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(sizeof(float) * 4 * 5)); - glVertexAttribDivisor(10, 1); - glEnableVertexAttribArray(11); //color - glVertexAttribPointer(11, 4, GL_FLOAT, GL_FALSE, stride, NULL); - glVertexAttribDivisor(11, 1); - glEnableVertexAttribArray(12); //custom - glVertexAttribPointer(12, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(sizeof(float) * 4 * 2)); - glVertexAttribDivisor(12, 1); -#ifdef DEBUG_ENABLED - - if (state.debug_draw == VS::VIEWPORT_DEBUG_DRAW_WIREFRAME && s->array_wireframe_id) { - - glDrawElementsInstanced(GL_LINES, s->index_wireframe_len, GL_UNSIGNED_INT, 0, split); - storage->info.render.vertices_count += s->index_array_len * split; - } else -#endif - if (s->index_array_len > 0) { - - glDrawElementsInstanced(gl_primitive[s->primitive], s->index_array_len, (s->array_len >= (1 << 16)) ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT, 0, split); - - storage->info.render.vertices_count += s->index_array_len * split; - - } else { - - glDrawArraysInstanced(gl_primitive[s->primitive], 0, s->array_len, split); - - storage->info.render.vertices_count += s->array_len * split; - } - } - - } else { - -#ifdef DEBUG_ENABLED - - if (state.debug_draw == VS::VIEWPORT_DEBUG_DRAW_WIREFRAME && s->array_wireframe_id) { - - glDrawElementsInstanced(GL_LINES, s->index_wireframe_len, GL_UNSIGNED_INT, 0, amount); - storage->info.render.vertices_count += s->index_array_len * amount; - } else -#endif - - if (s->index_array_len > 0) { - - glDrawElementsInstanced(gl_primitive[s->primitive], s->index_array_len, (s->array_len >= (1 << 16)) ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT, 0, amount); - - storage->info.render.vertices_count += s->index_array_len * amount; - - } else { - - glDrawArraysInstanced(gl_primitive[s->primitive], 0, s->array_len, amount); - - storage->info.render.vertices_count += s->array_len * amount; - } - } - - } break; - default: { - } - } -} - -void RasterizerSceneGLES3::_setup_light(RenderList::Element *e, const Transform &p_view_transform) { - - int omni_indices[16]; - int omni_count = 0; - int spot_indices[16]; - int spot_count = 0; - int reflection_indices[16]; - int reflection_count = 0; - - int maxobj = MIN(16, state.max_forward_lights_per_object); - - int lc = e->instance->light_instances.size(); - if (lc) { - - const RID *lights = e->instance->light_instances.ptr(); - - for (int i = 0; i < lc; i++) { - LightInstance *li = light_instance_owner.getornull(lights[i]); - if (!li || li->last_pass != render_pass) //not visible - continue; - - if (li && li->light_ptr->type == VS::LIGHT_OMNI) { - if (omni_count < maxobj && e->instance->layer_mask & li->light_ptr->cull_mask) { - omni_indices[omni_count++] = li->light_index; - } - } - - if (li && li->light_ptr->type == VS::LIGHT_SPOT) { - if (spot_count < maxobj && e->instance->layer_mask & li->light_ptr->cull_mask) { - spot_indices[spot_count++] = li->light_index; - } - } - } - } - - state.scene_shader.set_uniform(SceneShaderGLES3::OMNI_LIGHT_COUNT, omni_count); - - if (omni_count) { - glUniform1iv(state.scene_shader.get_uniform(SceneShaderGLES3::OMNI_LIGHT_INDICES), omni_count, omni_indices); - } - - state.scene_shader.set_uniform(SceneShaderGLES3::SPOT_LIGHT_COUNT, spot_count); - if (spot_count) { - glUniform1iv(state.scene_shader.get_uniform(SceneShaderGLES3::SPOT_LIGHT_INDICES), spot_count, spot_indices); - } - - int rc = e->instance->reflection_probe_instances.size(); - - if (rc) { - - const RID *reflections = e->instance->reflection_probe_instances.ptr(); - - for (int i = 0; i < rc; i++) { - ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getptr(reflections[i]); - if (rpi->last_pass != render_pass) //not visible - continue; - - if (reflection_count < maxobj) { - reflection_indices[reflection_count++] = rpi->reflection_index; - } - } - } - - state.scene_shader.set_uniform(SceneShaderGLES3::REFLECTION_COUNT, reflection_count); - if (reflection_count) { - glUniform1iv(state.scene_shader.get_uniform(SceneShaderGLES3::REFLECTION_INDICES), reflection_count, reflection_indices); - } - - int gi_probe_count = e->instance->gi_probe_instances.size(); - if (gi_probe_count) { - const RID *ridp = e->instance->gi_probe_instances.ptr(); - - GIProbeInstance *gipi = gi_probe_instance_owner.getptr(ridp[0]); - - float bias_scale = e->instance->baked_light ? 1 : 0; - glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 9); - glBindTexture(GL_TEXTURE_3D, gipi->tex_cache); - state.scene_shader.set_uniform(SceneShaderGLES3::GI_PROBE_XFORM1, gipi->transform_to_data * p_view_transform); - state.scene_shader.set_uniform(SceneShaderGLES3::GI_PROBE_BOUNDS1, gipi->bounds); - state.scene_shader.set_uniform(SceneShaderGLES3::GI_PROBE_MULTIPLIER1, gipi->probe ? gipi->probe->dynamic_range * gipi->probe->energy : 0.0); - state.scene_shader.set_uniform(SceneShaderGLES3::GI_PROBE_BIAS1, gipi->probe ? gipi->probe->bias * bias_scale : 0.0); - state.scene_shader.set_uniform(SceneShaderGLES3::GI_PROBE_NORMAL_BIAS1, gipi->probe ? gipi->probe->normal_bias * bias_scale : 0.0); - state.scene_shader.set_uniform(SceneShaderGLES3::GI_PROBE_BLEND_AMBIENT1, gipi->probe ? !gipi->probe->interior : false); - state.scene_shader.set_uniform(SceneShaderGLES3::GI_PROBE_CELL_SIZE1, gipi->cell_size_cache); - if (gi_probe_count > 1) { - - GIProbeInstance *gipi2 = gi_probe_instance_owner.getptr(ridp[1]); - - glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 10); - glBindTexture(GL_TEXTURE_3D, gipi2->tex_cache); - state.scene_shader.set_uniform(SceneShaderGLES3::GI_PROBE_XFORM2, gipi2->transform_to_data * p_view_transform); - state.scene_shader.set_uniform(SceneShaderGLES3::GI_PROBE_BOUNDS2, gipi2->bounds); - state.scene_shader.set_uniform(SceneShaderGLES3::GI_PROBE_CELL_SIZE2, gipi2->cell_size_cache); - state.scene_shader.set_uniform(SceneShaderGLES3::GI_PROBE_MULTIPLIER2, gipi2->probe ? gipi2->probe->dynamic_range * gipi2->probe->energy : 0.0); - state.scene_shader.set_uniform(SceneShaderGLES3::GI_PROBE_BIAS2, gipi2->probe ? gipi2->probe->bias * bias_scale : 0.0); - state.scene_shader.set_uniform(SceneShaderGLES3::GI_PROBE_NORMAL_BIAS2, gipi2->probe ? gipi2->probe->normal_bias * bias_scale : 0.0); - state.scene_shader.set_uniform(SceneShaderGLES3::GI_PROBE_BLEND_AMBIENT2, gipi2->probe ? !gipi2->probe->interior : false); - state.scene_shader.set_uniform(SceneShaderGLES3::GI_PROBE2_ENABLED, true); - } else { - - state.scene_shader.set_uniform(SceneShaderGLES3::GI_PROBE2_ENABLED, false); - } - } else if (!e->instance->lightmap_capture_data.empty()) { - - glUniform4fv(state.scene_shader.get_uniform_location(SceneShaderGLES3::LIGHTMAP_CAPTURES), 12, (const GLfloat *)e->instance->lightmap_capture_data.ptr()); - state.scene_shader.set_uniform(SceneShaderGLES3::LIGHTMAP_CAPTURE_SKY, false); - - } else if (e->instance->lightmap.is_valid()) { - RasterizerStorageGLES3::Texture *lightmap = storage->texture_owner.getornull(e->instance->lightmap); - RasterizerStorageGLES3::LightmapCapture *capture = storage->lightmap_capture_data_owner.getornull(e->instance->lightmap_capture->base); - - if (lightmap && capture) { - glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 9); - glBindTexture(GL_TEXTURE_2D, lightmap->tex_id); - state.scene_shader.set_uniform(SceneShaderGLES3::LIGHTMAP_ENERGY, capture->energy); - } - } -} - -void RasterizerSceneGLES3::_set_cull(bool p_front, bool p_disabled, bool p_reverse_cull) { - - bool front = p_front; - if (p_reverse_cull) - front = !front; - - if (p_disabled != state.cull_disabled) { - if (p_disabled) - glDisable(GL_CULL_FACE); - else - glEnable(GL_CULL_FACE); - - state.cull_disabled = p_disabled; - } - - if (front != state.cull_front) { - - glCullFace(front ? GL_FRONT : GL_BACK); - state.cull_front = front; - } -} - -void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements, int p_element_count, const Transform &p_view_transform, const CameraMatrix &p_projection, RasterizerStorageGLES3::Sky *p_sky, bool p_reverse_cull, bool p_alpha_pass, bool p_shadow, bool p_directional_add, bool p_directional_shadows) { - - glBindBufferBase(GL_UNIFORM_BUFFER, 0, state.scene_ubo); //bind globals ubo - - bool use_radiance_map = false; - if (!p_shadow && !p_directional_add) { - glBindBufferBase(GL_UNIFORM_BUFFER, 2, state.env_radiance_ubo); //bind environment radiance info - - if (p_sky != NULL) { - glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 2); - if (storage->config.use_texture_array_environment) { - glBindTexture(GL_TEXTURE_2D_ARRAY, p_sky->radiance); - } else { - glBindTexture(GL_TEXTURE_2D, p_sky->radiance); - } - glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 6); - glBindTexture(GL_TEXTURE_2D, p_sky->irradiance); - state.scene_shader.set_conditional(SceneShaderGLES3::USE_RADIANCE_MAP, true); - state.scene_shader.set_conditional(SceneShaderGLES3::USE_RADIANCE_MAP_ARRAY, storage->config.use_texture_array_environment); - use_radiance_map = true; - } else { - state.scene_shader.set_conditional(SceneShaderGLES3::USE_RADIANCE_MAP, false); - state.scene_shader.set_conditional(SceneShaderGLES3::USE_RADIANCE_MAP_ARRAY, false); - } - } else { - - state.scene_shader.set_conditional(SceneShaderGLES3::USE_RADIANCE_MAP, false); - state.scene_shader.set_conditional(SceneShaderGLES3::USE_RADIANCE_MAP_ARRAY, false); - } - - state.cull_front = false; - state.cull_disabled = false; - glCullFace(GL_BACK); - glEnable(GL_CULL_FACE); - - state.current_depth_test = true; - glEnable(GL_DEPTH_TEST); - - state.scene_shader.set_conditional(SceneShaderGLES3::USE_SKELETON, false); - - state.current_blend_mode = -1; - state.current_line_width = -1; - state.current_depth_draw = -1; - - RasterizerStorageGLES3::Material *prev_material = NULL; - RasterizerStorageGLES3::Geometry *prev_geometry = NULL; - RasterizerStorageGLES3::GeometryOwner *prev_owner = NULL; - VS::InstanceType prev_base_type = VS::INSTANCE_MAX; - - int current_blend_mode = -1; - - int prev_shading = -1; - RasterizerStorageGLES3::Skeleton *prev_skeleton = NULL; - - state.scene_shader.set_conditional(SceneShaderGLES3::SHADELESS, true); //by default unshaded (easier to set) - - bool first = true; - bool prev_use_instancing = false; - - storage->info.render.draw_call_count += p_element_count; - bool prev_opaque_prepass = false; - - for (int i = 0; i < p_element_count; i++) { - - RenderList::Element *e = p_elements[i]; - RasterizerStorageGLES3::Material *material = e->material; - RasterizerStorageGLES3::Skeleton *skeleton = NULL; - if (e->instance->skeleton.is_valid()) { - skeleton = storage->skeleton_owner.getornull(e->instance->skeleton); - } - - bool rebind = first; - - int shading = (e->sort_key >> RenderList::SORT_KEY_SHADING_SHIFT) & RenderList::SORT_KEY_SHADING_MASK; - - if (!p_shadow) { - - if (p_directional_add) { - if (e->sort_key & SORT_KEY_UNSHADED_FLAG || !(e->instance->layer_mask & directional_light->light_ptr->cull_mask)) { - continue; - } - - shading &= ~1; //ignore the ignore directional for base pass - } - - if (shading != prev_shading) { - - if (e->sort_key & SORT_KEY_UNSHADED_FLAG) { - - state.scene_shader.set_conditional(SceneShaderGLES3::SHADELESS, true); - state.scene_shader.set_conditional(SceneShaderGLES3::USE_FORWARD_LIGHTING, false); - state.scene_shader.set_conditional(SceneShaderGLES3::USE_VERTEX_LIGHTING, false); - state.scene_shader.set_conditional(SceneShaderGLES3::USE_LIGHT_DIRECTIONAL, false); - state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_DIRECTIONAL_SHADOW, false); - state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_USE_PSSM4, false); - state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_USE_PSSM2, false); - state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_USE_PSSM_BLEND, false); - state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_USE_PSSM_BLEND, false); - state.scene_shader.set_conditional(SceneShaderGLES3::SHADOW_MODE_PCF_5, false); - state.scene_shader.set_conditional(SceneShaderGLES3::SHADOW_MODE_PCF_13, false); - state.scene_shader.set_conditional(SceneShaderGLES3::USE_GI_PROBES, false); - state.scene_shader.set_conditional(SceneShaderGLES3::USE_LIGHTMAP_CAPTURE, false); - state.scene_shader.set_conditional(SceneShaderGLES3::USE_LIGHTMAP, false); - state.scene_shader.set_conditional(SceneShaderGLES3::USE_RADIANCE_MAP, false); - state.scene_shader.set_conditional(SceneShaderGLES3::USE_CONTACT_SHADOWS, false); - - //state.scene_shader.set_conditional(SceneShaderGLES3::SHADELESS,true); - } else { - - state.scene_shader.set_conditional(SceneShaderGLES3::USE_GI_PROBES, e->instance->gi_probe_instances.size() > 0); - state.scene_shader.set_conditional(SceneShaderGLES3::USE_LIGHTMAP, e->instance->lightmap.is_valid() && e->instance->gi_probe_instances.size() == 0); - state.scene_shader.set_conditional(SceneShaderGLES3::USE_LIGHTMAP_CAPTURE, !e->instance->lightmap_capture_data.empty() && !e->instance->lightmap.is_valid() && e->instance->gi_probe_instances.size() == 0); - - state.scene_shader.set_conditional(SceneShaderGLES3::SHADELESS, false); - - state.scene_shader.set_conditional(SceneShaderGLES3::USE_FORWARD_LIGHTING, !p_directional_add); - state.scene_shader.set_conditional(SceneShaderGLES3::USE_VERTEX_LIGHTING, (e->sort_key & SORT_KEY_VERTEX_LIT_FLAG)); - - state.scene_shader.set_conditional(SceneShaderGLES3::USE_LIGHT_DIRECTIONAL, false); - state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_DIRECTIONAL_SHADOW, false); - state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_USE_PSSM4, false); - state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_USE_PSSM2, false); - state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_USE_PSSM_BLEND, false); - state.scene_shader.set_conditional(SceneShaderGLES3::SHADOW_MODE_PCF_5, shadow_filter_mode == SHADOW_FILTER_PCF5); - state.scene_shader.set_conditional(SceneShaderGLES3::SHADOW_MODE_PCF_13, shadow_filter_mode == SHADOW_FILTER_PCF13); - state.scene_shader.set_conditional(SceneShaderGLES3::USE_RADIANCE_MAP, use_radiance_map); - state.scene_shader.set_conditional(SceneShaderGLES3::USE_CONTACT_SHADOWS, state.used_contact_shadows); - - if (p_directional_add || (directional_light && (e->sort_key & SORT_KEY_NO_DIRECTIONAL_FLAG) == 0)) { - state.scene_shader.set_conditional(SceneShaderGLES3::USE_LIGHT_DIRECTIONAL, true); - - if (p_directional_shadows && directional_light->light_ptr->shadow) { - state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_DIRECTIONAL_SHADOW, true); - - switch (directional_light->light_ptr->directional_shadow_mode) { - case VS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL: - break; //none - case VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS: - state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_USE_PSSM2, true); - state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_USE_PSSM_BLEND, directional_light->light_ptr->directional_blend_splits); - break; - case VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS: - state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_USE_PSSM4, true); - state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_USE_PSSM_BLEND, directional_light->light_ptr->directional_blend_splits); - break; - } - } - } - } - - rebind = true; - } - - if (p_alpha_pass || p_directional_add) { - int desired_blend_mode; - if (p_directional_add) { - desired_blend_mode = RasterizerStorageGLES3::Shader::Spatial::BLEND_MODE_ADD; - } else { - desired_blend_mode = material->shader->spatial.blend_mode; - } - - if (desired_blend_mode != current_blend_mode) { - - switch (desired_blend_mode) { - - case RasterizerStorageGLES3::Shader::Spatial::BLEND_MODE_MIX: { - glBlendEquation(GL_FUNC_ADD); - if (storage->frame.current_rt && storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]) { - glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - } else { - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - } - - } break; - case RasterizerStorageGLES3::Shader::Spatial::BLEND_MODE_ADD: { - - glBlendEquation(GL_FUNC_ADD); - glBlendFunc(p_alpha_pass ? GL_SRC_ALPHA : GL_ONE, GL_ONE); - - } break; - case RasterizerStorageGLES3::Shader::Spatial::BLEND_MODE_SUB: { - - glBlendEquation(GL_FUNC_REVERSE_SUBTRACT); - glBlendFunc(GL_SRC_ALPHA, GL_ONE); - } break; - case RasterizerStorageGLES3::Shader::Spatial::BLEND_MODE_MUL: { - glBlendEquation(GL_FUNC_ADD); - if (storage->frame.current_rt && storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]) { - glBlendFuncSeparate(GL_DST_COLOR, GL_ZERO, GL_DST_ALPHA, GL_ZERO); - } else { - glBlendFuncSeparate(GL_DST_COLOR, GL_ZERO, GL_ZERO, GL_ONE); - } - - } break; - } - - current_blend_mode = desired_blend_mode; - } - } - } - - bool use_opaque_prepass = e->sort_key & RenderList::SORT_KEY_OPAQUE_PRE_PASS; - - if (use_opaque_prepass != prev_opaque_prepass) { - state.scene_shader.set_conditional(SceneShaderGLES3::USE_OPAQUE_PREPASS, use_opaque_prepass); - rebind = true; - } - - bool use_instancing = e->instance->base_type == VS::INSTANCE_MULTIMESH || e->instance->base_type == VS::INSTANCE_PARTICLES; - - if (use_instancing != prev_use_instancing) { - state.scene_shader.set_conditional(SceneShaderGLES3::USE_INSTANCING, use_instancing); - rebind = true; - } - - if (prev_skeleton != skeleton) { - if ((prev_skeleton == NULL) != (skeleton == NULL)) { - state.scene_shader.set_conditional(SceneShaderGLES3::USE_SKELETON, skeleton != NULL); - rebind = true; - } - - if (skeleton) { - glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 1); - glBindTexture(GL_TEXTURE_2D, skeleton->texture); - } - } - - if (material != prev_material || rebind) { - - storage->info.render.material_switch_count++; - - rebind = _setup_material(material, use_opaque_prepass, p_alpha_pass); - - if (rebind) { - storage->info.render.shader_rebind_count++; - } - } - - if (!(e->sort_key & SORT_KEY_UNSHADED_FLAG) && !p_directional_add && !p_shadow) { - _setup_light(e, p_view_transform); - } - - if (e->owner != prev_owner || prev_base_type != e->instance->base_type || prev_geometry != e->geometry) { - - _setup_geometry(e, p_view_transform); - storage->info.render.surface_switch_count++; - } - - _set_cull(e->sort_key & RenderList::SORT_KEY_MIRROR_FLAG, e->sort_key & RenderList::SORT_KEY_CULL_DISABLED_FLAG, p_reverse_cull); - - state.scene_shader.set_uniform(SceneShaderGLES3::WORLD_TRANSFORM, e->instance->transform); - - _render_geometry(e); - - prev_material = material; - prev_base_type = e->instance->base_type; - prev_geometry = e->geometry; - prev_owner = e->owner; - prev_shading = shading; - prev_skeleton = skeleton; - prev_use_instancing = use_instancing; - prev_opaque_prepass = use_opaque_prepass; - first = false; - } - - glBindVertexArray(0); - - state.scene_shader.set_conditional(SceneShaderGLES3::USE_INSTANCING, false); - state.scene_shader.set_conditional(SceneShaderGLES3::USE_SKELETON, false); - state.scene_shader.set_conditional(SceneShaderGLES3::USE_RADIANCE_MAP, false); - state.scene_shader.set_conditional(SceneShaderGLES3::USE_FORWARD_LIGHTING, false); - state.scene_shader.set_conditional(SceneShaderGLES3::USE_LIGHT_DIRECTIONAL, false); - state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_DIRECTIONAL_SHADOW, false); - state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_USE_PSSM4, false); - state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_USE_PSSM2, false); - state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_USE_PSSM_BLEND, false); - state.scene_shader.set_conditional(SceneShaderGLES3::SHADELESS, false); - state.scene_shader.set_conditional(SceneShaderGLES3::SHADOW_MODE_PCF_5, false); - state.scene_shader.set_conditional(SceneShaderGLES3::SHADOW_MODE_PCF_13, false); - state.scene_shader.set_conditional(SceneShaderGLES3::USE_GI_PROBES, false); - state.scene_shader.set_conditional(SceneShaderGLES3::USE_LIGHTMAP, false); - state.scene_shader.set_conditional(SceneShaderGLES3::USE_LIGHTMAP_CAPTURE, false); - state.scene_shader.set_conditional(SceneShaderGLES3::USE_CONTACT_SHADOWS, false); - state.scene_shader.set_conditional(SceneShaderGLES3::USE_VERTEX_LIGHTING, false); - state.scene_shader.set_conditional(SceneShaderGLES3::USE_OPAQUE_PREPASS, false); -} - -void RasterizerSceneGLES3::_add_geometry(RasterizerStorageGLES3::Geometry *p_geometry, InstanceBase *p_instance, RasterizerStorageGLES3::GeometryOwner *p_owner, int p_material, bool p_depth_pass, bool p_shadow_pass) { - - RasterizerStorageGLES3::Material *m = NULL; - RID m_src = p_instance->material_override.is_valid() ? p_instance->material_override : (p_material >= 0 ? p_instance->materials[p_material] : p_geometry->material); - - if (state.debug_draw == VS::VIEWPORT_DEBUG_DRAW_OVERDRAW) { - m_src = default_overdraw_material; - } - - /* -#ifdef DEBUG_ENABLED - if (current_debug==VS::SCENARIO_DEBUG_OVERDRAW) { - m_src=overdraw_material; - } - -#endif -*/ - - if (m_src.is_valid()) { - m = storage->material_owner.getornull(m_src); - - if (!m->shader || !m->shader->valid) { - m = NULL; - } - } - - if (!m) { - m = storage->material_owner.getptr(default_material); - } - - ERR_FAIL_COND(!m); - - _add_geometry_with_material(p_geometry, p_instance, p_owner, m, p_depth_pass, p_shadow_pass); - - while (m->next_pass.is_valid()) { - m = storage->material_owner.getornull(m->next_pass); - if (!m || !m->shader || !m->shader->valid) - break; - _add_geometry_with_material(p_geometry, p_instance, p_owner, m, p_depth_pass, p_shadow_pass); - } -} - -void RasterizerSceneGLES3::_add_geometry_with_material(RasterizerStorageGLES3::Geometry *p_geometry, InstanceBase *p_instance, RasterizerStorageGLES3::GeometryOwner *p_owner, RasterizerStorageGLES3::Material *p_material, bool p_depth_pass, bool p_shadow_pass) { - - bool has_base_alpha = (p_material->shader->spatial.uses_alpha && !p_material->shader->spatial.uses_alpha_scissor) || p_material->shader->spatial.uses_screen_texture || p_material->shader->spatial.uses_depth_texture; - bool has_blend_alpha = p_material->shader->spatial.blend_mode != RasterizerStorageGLES3::Shader::Spatial::BLEND_MODE_MIX; - bool has_alpha = has_base_alpha || has_blend_alpha; - - bool mirror = p_instance->mirror; - bool no_cull = false; - - if (p_material->shader->spatial.cull_mode == RasterizerStorageGLES3::Shader::Spatial::CULL_MODE_DISABLED) { - no_cull = true; - mirror = false; - } else if (p_material->shader->spatial.cull_mode == RasterizerStorageGLES3::Shader::Spatial::CULL_MODE_FRONT) { - mirror = !mirror; - } - - if (p_material->shader->spatial.uses_sss) { - state.used_sss = true; - } - - if (p_material->shader->spatial.uses_screen_texture) { - state.used_screen_texture = true; - } - - if (p_material->shader->spatial.uses_depth_texture) { - state.used_depth_texture = true; - } - - if (p_depth_pass) { - - if (has_blend_alpha || p_material->shader->spatial.uses_depth_texture || (has_base_alpha && p_material->shader->spatial.depth_draw_mode != RasterizerStorageGLES3::Shader::Spatial::DEPTH_DRAW_ALPHA_PREPASS) || p_material->shader->spatial.depth_draw_mode == RasterizerStorageGLES3::Shader::Spatial::DEPTH_DRAW_NEVER || p_material->shader->spatial.no_depth_test || p_instance->cast_shadows == VS::SHADOW_CASTING_SETTING_OFF) - return; //bye - - if (!p_material->shader->spatial.uses_alpha_scissor && !p_material->shader->spatial.writes_modelview_or_projection && !p_material->shader->spatial.uses_vertex && !p_material->shader->spatial.uses_discard && p_material->shader->spatial.depth_draw_mode != RasterizerStorageGLES3::Shader::Spatial::DEPTH_DRAW_ALPHA_PREPASS) { - //shader does not use discard and does not write a vertex position, use generic material - if (p_instance->cast_shadows == VS::SHADOW_CASTING_SETTING_DOUBLE_SIDED) { - p_material = storage->material_owner.getptr(!p_shadow_pass && p_material->shader->spatial.uses_world_coordinates ? default_worldcoord_material_twosided : default_material_twosided); - no_cull = true; - mirror = false; - } else { - p_material = storage->material_owner.getptr(!p_shadow_pass && p_material->shader->spatial.uses_world_coordinates ? default_worldcoord_material : default_material); - } - } - - has_alpha = false; - } - - RenderList::Element *e = (has_alpha || p_material->shader->spatial.no_depth_test) ? render_list.add_alpha_element() : render_list.add_element(); - - if (!e) - return; - - e->geometry = p_geometry; - e->material = p_material; - e->instance = p_instance; - e->owner = p_owner; - e->sort_key = 0; - - if (e->geometry->last_pass != render_pass) { - e->geometry->last_pass = render_pass; - e->geometry->index = current_geometry_index++; - } - - if (!p_depth_pass && directional_light && (directional_light->light_ptr->cull_mask & e->instance->layer_mask) == 0) { - e->sort_key |= SORT_KEY_NO_DIRECTIONAL_FLAG; - } - - e->sort_key |= uint64_t(e->geometry->index) << RenderList::SORT_KEY_GEOMETRY_INDEX_SHIFT; - e->sort_key |= uint64_t(e->instance->base_type) << RenderList::SORT_KEY_GEOMETRY_TYPE_SHIFT; - - if (e->material->last_pass != render_pass) { - e->material->last_pass = render_pass; - e->material->index = current_material_index++; - } - - e->sort_key |= uint64_t(e->material->index) << RenderList::SORT_KEY_MATERIAL_INDEX_SHIFT; - e->sort_key |= uint64_t(e->instance->depth_layer) << RenderList::SORT_KEY_OPAQUE_DEPTH_LAYER_SHIFT; - - if (!p_depth_pass) { - - if (e->instance->gi_probe_instances.size()) { - e->sort_key |= SORT_KEY_GI_PROBES_FLAG; - } - - if (e->instance->lightmap.is_valid()) { - e->sort_key |= SORT_KEY_LIGHTMAP_FLAG; - } - - if (!e->instance->lightmap_capture_data.empty()) { - e->sort_key |= SORT_KEY_LIGHTMAP_CAPTURE_FLAG; - } - - e->sort_key |= (uint64_t(p_material->render_priority) + 128) << RenderList::SORT_KEY_PRIORITY_SHIFT; - } - - /* - if (e->geometry->type==RasterizerStorageGLES3::Geometry::GEOMETRY_MULTISURFACE) - e->sort_flags|=RenderList::SORT_FLAG_INSTANCING; - */ - - if (mirror) { - e->sort_key |= RenderList::SORT_KEY_MIRROR_FLAG; - } - - if (no_cull) { - e->sort_key |= RenderList::SORT_KEY_CULL_DISABLED_FLAG; - } - - //e->light_type=0xFF; // no lights! - - if (p_depth_pass || p_material->shader->spatial.unshaded || state.debug_draw == VS::VIEWPORT_DEBUG_DRAW_UNSHADED) { - e->sort_key |= SORT_KEY_UNSHADED_FLAG; - } - - if (p_depth_pass && p_material->shader->spatial.depth_draw_mode == RasterizerStorageGLES3::Shader::Spatial::DEPTH_DRAW_ALPHA_PREPASS) { - e->sort_key |= RenderList::SORT_KEY_OPAQUE_PRE_PASS; - } - - if (!p_depth_pass && (p_material->shader->spatial.uses_vertex_lighting || storage->config.force_vertex_shading)) { - - e->sort_key |= SORT_KEY_VERTEX_LIT_FLAG; - } - - if (p_material->shader->spatial.uses_time) { - VisualServerRaster::redraw_request(); - } -} - -void RasterizerSceneGLES3::_draw_sky(RasterizerStorageGLES3::Sky *p_sky, const CameraMatrix &p_projection, const Transform &p_transform, bool p_vflip, float p_custom_fov, float p_energy, const Basis &p_sky_orientation) { - - ERR_FAIL_COND(!p_sky); - - RasterizerStorageGLES3::Texture *tex = storage->texture_owner.getornull(p_sky->panorama); - - ERR_FAIL_COND(!tex); - glActiveTexture(GL_TEXTURE0); - - tex = tex->get_ptr(); //resolve for proxies - - glBindTexture(tex->target, tex->tex_id); - - if (storage->config.srgb_decode_supported && tex->srgb && !tex->using_srgb) { - - glTexParameteri(tex->target, _TEXTURE_SRGB_DECODE_EXT, _DECODE_EXT); - tex->using_srgb = true; -#ifdef TOOLS_ENABLED - if (!(tex->flags & VS::TEXTURE_FLAG_CONVERT_TO_LINEAR)) { - tex->flags |= VS::TEXTURE_FLAG_CONVERT_TO_LINEAR; - //notify that texture must be set to linear beforehand, so it works in other platforms when exported - } -#endif - } - - glDepthMask(GL_TRUE); - glEnable(GL_DEPTH_TEST); - glDisable(GL_CULL_FACE); - glDisable(GL_BLEND); - glDepthFunc(GL_LEQUAL); - glColorMask(1, 1, 1, 1); - - // Camera - CameraMatrix camera; - - if (p_custom_fov) { - - float near_plane = p_projection.get_z_near(); - float far_plane = p_projection.get_z_far(); - float aspect = p_projection.get_aspect(); - - camera.set_perspective(p_custom_fov, aspect, near_plane, far_plane); - - } else { - camera = p_projection; - } - - float flip_sign = p_vflip ? -1 : 1; - - /* - If matrix[2][0] or matrix[2][1] we're dealing with an asymmetrical projection matrix. This is the case for stereoscopic rendering (i.e. VR). - To ensure the image rendered is perspective correct we need to move some logic into the shader. For this the USE_ASYM_PANO option is introduced. - It also means the uv coordinates are ignored in this mode and we don't need our loop. - */ - bool asymmetrical = ((camera.matrix[2][0] != 0.0) || (camera.matrix[2][1] != 0.0)); - - Vector3 vertices[8] = { - Vector3(-1, -1 * flip_sign, 1), - Vector3(0, 1, 0), - Vector3(1, -1 * flip_sign, 1), - Vector3(1, 1, 0), - Vector3(1, 1 * flip_sign, 1), - Vector3(1, 0, 0), - Vector3(-1, 1 * flip_sign, 1), - Vector3(0, 0, 0) - }; - - if (!asymmetrical) { - Vector2 vp_he = camera.get_viewport_half_extents(); - float zn; - zn = p_projection.get_z_near(); - - for (int i = 0; i < 4; i++) { - Vector3 uv = vertices[i * 2 + 1]; - uv.x = (uv.x * 2.0 - 1.0) * vp_he.x; - uv.y = -(uv.y * 2.0 - 1.0) * vp_he.y; - uv.z = -zn; - vertices[i * 2 + 1] = p_transform.basis.xform(uv).normalized(); - vertices[i * 2 + 1].z = -vertices[i * 2 + 1].z; - } - } - - glBindBuffer(GL_ARRAY_BUFFER, state.sky_verts); - glBufferData(GL_ARRAY_BUFFER, sizeof(Vector3) * 8, vertices, GL_DYNAMIC_DRAW); - glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind - - glBindVertexArray(state.sky_array); - - storage->shaders.copy.set_conditional(CopyShaderGLES3::USE_ASYM_PANO, asymmetrical); - storage->shaders.copy.set_conditional(CopyShaderGLES3::USE_PANORAMA, !asymmetrical); - storage->shaders.copy.set_conditional(CopyShaderGLES3::USE_MULTIPLIER, true); - storage->shaders.copy.bind(); - - storage->shaders.copy.set_uniform(CopyShaderGLES3::MULTIPLIER, p_energy); - - // don't know why but I always have problems setting a uniform mat3, so we're using a transform - storage->shaders.copy.set_uniform(CopyShaderGLES3::SKY_TRANSFORM, Transform(p_sky_orientation, Vector3(0.0, 0.0, 0.0)).affine_inverse()); - - if (asymmetrical) { - // pack the bits we need from our projection matrix - storage->shaders.copy.set_uniform(CopyShaderGLES3::ASYM_PROJ, camera.matrix[2][0], camera.matrix[0][0], camera.matrix[2][1], camera.matrix[1][1]); - ///@TODO I couldn't get mat3 + p_transform.basis to work, that would be better here. - storage->shaders.copy.set_uniform(CopyShaderGLES3::PANO_TRANSFORM, p_transform); - } - - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - - glBindVertexArray(0); - glColorMask(1, 1, 1, 1); - - storage->shaders.copy.set_conditional(CopyShaderGLES3::USE_ASYM_PANO, false); - storage->shaders.copy.set_conditional(CopyShaderGLES3::USE_MULTIPLIER, false); - storage->shaders.copy.set_conditional(CopyShaderGLES3::USE_PANORAMA, false); -} - -void RasterizerSceneGLES3::_setup_environment(Environment *env, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, bool p_no_fog) { - Transform sky_orientation; - - //store camera into ubo - store_camera(p_cam_projection, state.ubo_data.projection_matrix); - store_camera(p_cam_projection.inverse(), state.ubo_data.inv_projection_matrix); - store_transform(p_cam_transform, state.ubo_data.camera_matrix); - store_transform(p_cam_transform.affine_inverse(), state.ubo_data.camera_inverse_matrix); - - //time global variables - state.ubo_data.time = storage->frame.time[0]; - - state.ubo_data.z_far = p_cam_projection.get_z_far(); - //bg and ambient - if (env) { - state.ubo_data.bg_energy = env->bg_energy; - state.ubo_data.ambient_energy = env->ambient_energy; - Color linear_ambient_color = env->ambient_color.to_linear(); - state.ubo_data.ambient_light_color[0] = linear_ambient_color.r; - state.ubo_data.ambient_light_color[1] = linear_ambient_color.g; - state.ubo_data.ambient_light_color[2] = linear_ambient_color.b; - state.ubo_data.ambient_light_color[3] = linear_ambient_color.a; - - Color bg_color; - - switch (env->bg_mode) { - case VS::ENV_BG_CLEAR_COLOR: { - bg_color = storage->frame.clear_request_color.to_linear(); - } break; - case VS::ENV_BG_COLOR: { - bg_color = env->bg_color.to_linear(); - } break; - default: { - bg_color = Color(0, 0, 0, 1); - } break; - } - - state.ubo_data.bg_color[0] = bg_color.r; - state.ubo_data.bg_color[1] = bg_color.g; - state.ubo_data.bg_color[2] = bg_color.b; - state.ubo_data.bg_color[3] = bg_color.a; - - //use the inverse of our sky_orientation, we may need to skip this if we're using a reflection probe? - sky_orientation = Transform(env->sky_orientation, Vector3(0.0, 0.0, 0.0)).affine_inverse(); - - state.env_radiance_data.ambient_contribution = env->ambient_sky_contribution; - state.ubo_data.ambient_occlusion_affect_light = env->ssao_light_affect; - state.ubo_data.ambient_occlusion_affect_ssao = env->ssao_ao_channel_affect; - - //fog - - Color linear_fog = env->fog_color.to_linear(); - state.ubo_data.fog_color_enabled[0] = linear_fog.r; - state.ubo_data.fog_color_enabled[1] = linear_fog.g; - state.ubo_data.fog_color_enabled[2] = linear_fog.b; - state.ubo_data.fog_color_enabled[3] = (!p_no_fog && env->fog_enabled) ? 1.0 : 0.0; - state.ubo_data.fog_density = linear_fog.a; - - Color linear_sun = env->fog_sun_color.to_linear(); - state.ubo_data.fog_sun_color_amount[0] = linear_sun.r; - state.ubo_data.fog_sun_color_amount[1] = linear_sun.g; - state.ubo_data.fog_sun_color_amount[2] = linear_sun.b; - state.ubo_data.fog_sun_color_amount[3] = env->fog_sun_amount; - state.ubo_data.fog_depth_enabled = env->fog_depth_enabled; - state.ubo_data.fog_depth_begin = env->fog_depth_begin; - state.ubo_data.fog_depth_end = env->fog_depth_end; - state.ubo_data.fog_depth_curve = env->fog_depth_curve; - state.ubo_data.fog_transmit_enabled = env->fog_transmit_enabled; - state.ubo_data.fog_transmit_curve = env->fog_transmit_curve; - state.ubo_data.fog_height_enabled = env->fog_height_enabled; - state.ubo_data.fog_height_min = env->fog_height_min; - state.ubo_data.fog_height_max = env->fog_height_max; - state.ubo_data.fog_height_curve = env->fog_height_curve; - - } else { - state.ubo_data.bg_energy = 1.0; - state.ubo_data.ambient_energy = 1.0; - //use from clear color instead, since there is no ambient - Color linear_ambient_color = storage->frame.clear_request_color.to_linear(); - state.ubo_data.ambient_light_color[0] = linear_ambient_color.r; - state.ubo_data.ambient_light_color[1] = linear_ambient_color.g; - state.ubo_data.ambient_light_color[2] = linear_ambient_color.b; - state.ubo_data.ambient_light_color[3] = linear_ambient_color.a; - - state.ubo_data.bg_color[0] = linear_ambient_color.r; - state.ubo_data.bg_color[1] = linear_ambient_color.g; - state.ubo_data.bg_color[2] = linear_ambient_color.b; - state.ubo_data.bg_color[3] = linear_ambient_color.a; - - state.env_radiance_data.ambient_contribution = 0; - state.ubo_data.ambient_occlusion_affect_light = 0; - - state.ubo_data.fog_color_enabled[3] = 0.0; - } - - { - //directional shadow - - state.ubo_data.shadow_directional_pixel_size[0] = 1.0 / directional_shadow.size; - state.ubo_data.shadow_directional_pixel_size[1] = 1.0 / directional_shadow.size; - - glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 4); - glBindTexture(GL_TEXTURE_2D, directional_shadow.depth); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LESS); - } - - glBindBuffer(GL_UNIFORM_BUFFER, state.scene_ubo); - glBufferData(GL_UNIFORM_BUFFER, sizeof(State::SceneDataUBO), &state.ubo_data, GL_DYNAMIC_DRAW); - glBindBuffer(GL_UNIFORM_BUFFER, 0); - - //fill up environment - - store_transform(sky_orientation * p_cam_transform, state.env_radiance_data.transform); - - glBindBuffer(GL_UNIFORM_BUFFER, state.env_radiance_ubo); - glBufferData(GL_UNIFORM_BUFFER, sizeof(State::EnvironmentRadianceUBO), &state.env_radiance_data, GL_DYNAMIC_DRAW); - glBindBuffer(GL_UNIFORM_BUFFER, 0); -} - -void RasterizerSceneGLES3::_setup_directional_light(int p_index, const Transform &p_camera_inverse_transform, bool p_use_shadows) { - - LightInstance *li = directional_lights[p_index]; - - LightDataUBO ubo_data; //used for filling - - float sign = li->light_ptr->negative ? -1 : 1; - - Color linear_col = li->light_ptr->color.to_linear(); - //compensate normalized diffuse range by multiplying by PI - ubo_data.light_color_energy[0] = linear_col.r * sign * li->light_ptr->param[VS::LIGHT_PARAM_ENERGY] * Math_PI; - ubo_data.light_color_energy[1] = linear_col.g * sign * li->light_ptr->param[VS::LIGHT_PARAM_ENERGY] * Math_PI; - ubo_data.light_color_energy[2] = linear_col.b * sign * li->light_ptr->param[VS::LIGHT_PARAM_ENERGY] * Math_PI; - ubo_data.light_color_energy[3] = 0; - - //omni, keep at 0 - ubo_data.light_pos_inv_radius[0] = 0.0; - ubo_data.light_pos_inv_radius[1] = 0.0; - ubo_data.light_pos_inv_radius[2] = 0.0; - ubo_data.light_pos_inv_radius[3] = 0.0; - - Vector3 direction = p_camera_inverse_transform.basis.xform(li->transform.basis.xform(Vector3(0, 0, -1))).normalized(); - ubo_data.light_direction_attenuation[0] = direction.x; - ubo_data.light_direction_attenuation[1] = direction.y; - ubo_data.light_direction_attenuation[2] = direction.z; - ubo_data.light_direction_attenuation[3] = 1.0; - - ubo_data.light_params[0] = 0; - ubo_data.light_params[1] = 0; - ubo_data.light_params[2] = li->light_ptr->param[VS::LIGHT_PARAM_SPECULAR]; - ubo_data.light_params[3] = 0; - - Color shadow_color = li->light_ptr->shadow_color.to_linear(); - ubo_data.light_shadow_color_contact[0] = shadow_color.r; - ubo_data.light_shadow_color_contact[1] = shadow_color.g; - ubo_data.light_shadow_color_contact[2] = shadow_color.b; - ubo_data.light_shadow_color_contact[3] = li->light_ptr->param[VS::LIGHT_PARAM_CONTACT_SHADOW_SIZE]; - - if (p_use_shadows && li->light_ptr->shadow) { - - int shadow_count = 0; - - switch (li->light_ptr->directional_shadow_mode) { - case VS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL: { - shadow_count = 1; - } break; - case VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS: { - shadow_count = 2; - } break; - case VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS: { - shadow_count = 4; - } break; - } - - for (int j = 0; j < shadow_count; j++) { - - uint32_t x = li->directional_rect.position.x; - uint32_t y = li->directional_rect.position.y; - uint32_t width = li->directional_rect.size.x; - uint32_t height = li->directional_rect.size.y; - - if (li->light_ptr->directional_shadow_mode == VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS) { - - width /= 2; - height /= 2; - - if (j == 1) { - x += width; - } else if (j == 2) { - y += height; - } else if (j == 3) { - x += width; - y += height; - } - - } else if (li->light_ptr->directional_shadow_mode == VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS) { - - height /= 2; - - if (j != 0) { - y += height; - } - } - - ubo_data.shadow_split_offsets[j] = li->shadow_transform[j].split; - - Transform modelview = (p_camera_inverse_transform * li->shadow_transform[j].transform).affine_inverse(); - - CameraMatrix bias; - bias.set_light_bias(); - CameraMatrix rectm; - Rect2 atlas_rect = Rect2(float(x) / directional_shadow.size, float(y) / directional_shadow.size, float(width) / directional_shadow.size, float(height) / directional_shadow.size); - rectm.set_light_atlas_rect(atlas_rect); - - CameraMatrix shadow_mtx = rectm * bias * li->shadow_transform[j].camera * modelview; - - store_camera(shadow_mtx, &ubo_data.shadow.matrix[16 * j]); - - ubo_data.light_clamp[0] = atlas_rect.position.x; - ubo_data.light_clamp[1] = atlas_rect.position.y; - ubo_data.light_clamp[2] = atlas_rect.size.x; - ubo_data.light_clamp[3] = atlas_rect.size.y; - } - } - - glBindBuffer(GL_UNIFORM_BUFFER, state.directional_ubo); - glBufferData(GL_UNIFORM_BUFFER, sizeof(LightDataUBO), &ubo_data, GL_DYNAMIC_DRAW); - glBindBuffer(GL_UNIFORM_BUFFER, 0); - - directional_light = li; - - glBindBufferBase(GL_UNIFORM_BUFFER, 3, state.directional_ubo); -} - -void RasterizerSceneGLES3::_setup_lights(RID *p_light_cull_result, int p_light_cull_count, const Transform &p_camera_inverse_transform, const CameraMatrix &p_camera_projection, RID p_shadow_atlas) { - - state.omni_light_count = 0; - state.spot_light_count = 0; - state.directional_light_count = 0; - - directional_light = NULL; - - ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_shadow_atlas); - - for (int i = 0; i < p_light_cull_count; i++) { - - ERR_BREAK(i >= render_list.max_lights); - - LightInstance *li = light_instance_owner.getptr(p_light_cull_result[i]); - - LightDataUBO ubo_data; //used for filling - - switch (li->light_ptr->type) { - - case VS::LIGHT_DIRECTIONAL: { - - if (state.directional_light_count < RenderList::MAX_DIRECTIONAL_LIGHTS) { - directional_lights[state.directional_light_count++] = li; - } - - } break; - case VS::LIGHT_OMNI: { - - float sign = li->light_ptr->negative ? -1 : 1; - - Color linear_col = li->light_ptr->color.to_linear(); - ubo_data.light_color_energy[0] = linear_col.r * sign * li->light_ptr->param[VS::LIGHT_PARAM_ENERGY] * Math_PI; - ubo_data.light_color_energy[1] = linear_col.g * sign * li->light_ptr->param[VS::LIGHT_PARAM_ENERGY] * Math_PI; - ubo_data.light_color_energy[2] = linear_col.b * sign * li->light_ptr->param[VS::LIGHT_PARAM_ENERGY] * Math_PI; - ubo_data.light_color_energy[3] = 0; - - Vector3 pos = p_camera_inverse_transform.xform(li->transform.origin); - - //directional, keep at 0 - ubo_data.light_pos_inv_radius[0] = pos.x; - ubo_data.light_pos_inv_radius[1] = pos.y; - ubo_data.light_pos_inv_radius[2] = pos.z; - ubo_data.light_pos_inv_radius[3] = 1.0 / MAX(0.001, li->light_ptr->param[VS::LIGHT_PARAM_RANGE]); - - ubo_data.light_direction_attenuation[0] = 0; - ubo_data.light_direction_attenuation[1] = 0; - ubo_data.light_direction_attenuation[2] = 0; - ubo_data.light_direction_attenuation[3] = li->light_ptr->param[VS::LIGHT_PARAM_ATTENUATION]; - - ubo_data.light_params[0] = 0; - ubo_data.light_params[1] = 0; - ubo_data.light_params[2] = li->light_ptr->param[VS::LIGHT_PARAM_SPECULAR]; - ubo_data.light_params[3] = 0; - - Color shadow_color = li->light_ptr->shadow_color.to_linear(); - ubo_data.light_shadow_color_contact[0] = shadow_color.r; - ubo_data.light_shadow_color_contact[1] = shadow_color.g; - ubo_data.light_shadow_color_contact[2] = shadow_color.b; - ubo_data.light_shadow_color_contact[3] = li->light_ptr->param[VS::LIGHT_PARAM_CONTACT_SHADOW_SIZE]; - - if (li->light_ptr->shadow && shadow_atlas && shadow_atlas->shadow_owners.has(li->self)) { - // fill in the shadow information - - uint32_t key = shadow_atlas->shadow_owners[li->self]; - - uint32_t quadrant = (key >> ShadowAtlas::QUADRANT_SHIFT) & 0x3; - uint32_t shadow = key & ShadowAtlas::SHADOW_INDEX_MASK; - - ERR_CONTINUE(shadow >= (uint32_t)shadow_atlas->quadrants[quadrant].shadows.size()); - - uint32_t atlas_size = shadow_atlas->size; - uint32_t quadrant_size = atlas_size >> 1; - - uint32_t x = (quadrant & 1) * quadrant_size; - uint32_t y = (quadrant >> 1) * quadrant_size; - - uint32_t shadow_size = (quadrant_size / shadow_atlas->quadrants[quadrant].subdivision); - x += (shadow % shadow_atlas->quadrants[quadrant].subdivision) * shadow_size; - y += (shadow / shadow_atlas->quadrants[quadrant].subdivision) * shadow_size; - - uint32_t width = shadow_size; - uint32_t height = shadow_size; - - if (li->light_ptr->omni_shadow_detail == VS::LIGHT_OMNI_SHADOW_DETAIL_HORIZONTAL) { - - height /= 2; - } else { - width /= 2; - } - - Transform proj = (p_camera_inverse_transform * li->transform).inverse(); - - store_transform(proj, ubo_data.shadow.matrix1); - - ubo_data.light_params[3] = 1.0; //means it has shadow - ubo_data.light_clamp[0] = float(x) / atlas_size; - ubo_data.light_clamp[1] = float(y) / atlas_size; - ubo_data.light_clamp[2] = float(width) / atlas_size; - ubo_data.light_clamp[3] = float(height) / atlas_size; - } - - li->light_index = state.omni_light_count; - copymem(&state.omni_array_tmp[li->light_index * state.ubo_light_size], &ubo_data, state.ubo_light_size); - state.omni_light_count++; - - } break; - case VS::LIGHT_SPOT: { - - float sign = li->light_ptr->negative ? -1 : 1; - - Color linear_col = li->light_ptr->color.to_linear(); - ubo_data.light_color_energy[0] = linear_col.r * sign * li->light_ptr->param[VS::LIGHT_PARAM_ENERGY] * Math_PI; - ubo_data.light_color_energy[1] = linear_col.g * sign * li->light_ptr->param[VS::LIGHT_PARAM_ENERGY] * Math_PI; - ubo_data.light_color_energy[2] = linear_col.b * sign * li->light_ptr->param[VS::LIGHT_PARAM_ENERGY] * Math_PI; - ubo_data.light_color_energy[3] = 0; - - Vector3 pos = p_camera_inverse_transform.xform(li->transform.origin); - - //directional, keep at 0 - ubo_data.light_pos_inv_radius[0] = pos.x; - ubo_data.light_pos_inv_radius[1] = pos.y; - ubo_data.light_pos_inv_radius[2] = pos.z; - ubo_data.light_pos_inv_radius[3] = 1.0 / MAX(0.001, li->light_ptr->param[VS::LIGHT_PARAM_RANGE]); - - Vector3 direction = p_camera_inverse_transform.basis.xform(li->transform.basis.xform(Vector3(0, 0, -1))).normalized(); - ubo_data.light_direction_attenuation[0] = direction.x; - ubo_data.light_direction_attenuation[1] = direction.y; - ubo_data.light_direction_attenuation[2] = direction.z; - ubo_data.light_direction_attenuation[3] = li->light_ptr->param[VS::LIGHT_PARAM_ATTENUATION]; - - ubo_data.light_params[0] = li->light_ptr->param[VS::LIGHT_PARAM_SPOT_ATTENUATION]; - ubo_data.light_params[1] = Math::cos(Math::deg2rad(li->light_ptr->param[VS::LIGHT_PARAM_SPOT_ANGLE])); - ubo_data.light_params[2] = li->light_ptr->param[VS::LIGHT_PARAM_SPECULAR]; - ubo_data.light_params[3] = 0; - - Color shadow_color = li->light_ptr->shadow_color.to_linear(); - ubo_data.light_shadow_color_contact[0] = shadow_color.r; - ubo_data.light_shadow_color_contact[1] = shadow_color.g; - ubo_data.light_shadow_color_contact[2] = shadow_color.b; - ubo_data.light_shadow_color_contact[3] = li->light_ptr->param[VS::LIGHT_PARAM_CONTACT_SHADOW_SIZE]; - - if (li->light_ptr->shadow && shadow_atlas && shadow_atlas->shadow_owners.has(li->self)) { - // fill in the shadow information - - uint32_t key = shadow_atlas->shadow_owners[li->self]; - - uint32_t quadrant = (key >> ShadowAtlas::QUADRANT_SHIFT) & 0x3; - uint32_t shadow = key & ShadowAtlas::SHADOW_INDEX_MASK; - - ERR_CONTINUE(shadow >= (uint32_t)shadow_atlas->quadrants[quadrant].shadows.size()); - - uint32_t atlas_size = shadow_atlas->size; - uint32_t quadrant_size = atlas_size >> 1; - - uint32_t x = (quadrant & 1) * quadrant_size; - uint32_t y = (quadrant >> 1) * quadrant_size; - - uint32_t shadow_size = (quadrant_size / shadow_atlas->quadrants[quadrant].subdivision); - x += (shadow % shadow_atlas->quadrants[quadrant].subdivision) * shadow_size; - y += (shadow / shadow_atlas->quadrants[quadrant].subdivision) * shadow_size; - - uint32_t width = shadow_size; - uint32_t height = shadow_size; - - Rect2 rect(float(x) / atlas_size, float(y) / atlas_size, float(width) / atlas_size, float(height) / atlas_size); - - ubo_data.light_params[3] = 1.0; //means it has shadow - ubo_data.light_clamp[0] = rect.position.x; - ubo_data.light_clamp[1] = rect.position.y; - ubo_data.light_clamp[2] = rect.size.x; - ubo_data.light_clamp[3] = rect.size.y; - - Transform modelview = (p_camera_inverse_transform * li->transform).inverse(); - - CameraMatrix bias; - bias.set_light_bias(); - CameraMatrix rectm; - rectm.set_light_atlas_rect(rect); - - CameraMatrix shadow_mtx = rectm * bias * li->shadow_transform[0].camera * modelview; - - store_camera(shadow_mtx, ubo_data.shadow.matrix1); - } - - li->light_index = state.spot_light_count; - copymem(&state.spot_array_tmp[li->light_index * state.ubo_light_size], &ubo_data, state.ubo_light_size); - state.spot_light_count++; - } break; - } - - li->last_pass = render_pass; - - //update UBO for forward rendering, blit to texture for clustered - } - - if (state.omni_light_count) { - - glBindBuffer(GL_UNIFORM_BUFFER, state.omni_array_ubo); - glBufferSubData(GL_UNIFORM_BUFFER, 0, state.omni_light_count * state.ubo_light_size, state.omni_array_tmp); - glBindBuffer(GL_UNIFORM_BUFFER, 0); - } - - glBindBufferBase(GL_UNIFORM_BUFFER, 4, state.omni_array_ubo); - - if (state.spot_light_count) { - - glBindBuffer(GL_UNIFORM_BUFFER, state.spot_array_ubo); - glBufferSubData(GL_UNIFORM_BUFFER, 0, state.spot_light_count * state.ubo_light_size, state.spot_array_tmp); - glBindBuffer(GL_UNIFORM_BUFFER, 0); - } - - glBindBufferBase(GL_UNIFORM_BUFFER, 5, state.spot_array_ubo); -} - -void RasterizerSceneGLES3::_setup_reflections(RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, const Transform &p_camera_inverse_transform, const CameraMatrix &p_camera_projection, RID p_reflection_atlas, Environment *p_env) { - - state.reflection_probe_count = 0; - - for (int i = 0; i < p_reflection_probe_cull_count; i++) { - - ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_reflection_probe_cull_result[i]); - ERR_CONTINUE(!rpi); - - ReflectionAtlas *reflection_atlas = reflection_atlas_owner.getornull(p_reflection_atlas); - ERR_CONTINUE(!reflection_atlas); - - ERR_CONTINUE(rpi->reflection_atlas_index < 0); - - if (state.reflection_probe_count >= state.max_ubo_reflections) - break; - - rpi->last_pass = render_pass; - - ReflectionProbeDataUBO reflection_ubo; - - reflection_ubo.box_extents[0] = rpi->probe_ptr->extents.x; - reflection_ubo.box_extents[1] = rpi->probe_ptr->extents.y; - reflection_ubo.box_extents[2] = rpi->probe_ptr->extents.z; - reflection_ubo.box_extents[3] = 0; - - reflection_ubo.box_ofs[0] = rpi->probe_ptr->origin_offset.x; - reflection_ubo.box_ofs[1] = rpi->probe_ptr->origin_offset.y; - reflection_ubo.box_ofs[2] = rpi->probe_ptr->origin_offset.z; - reflection_ubo.box_ofs[3] = 0; - - reflection_ubo.params[0] = rpi->probe_ptr->intensity; - reflection_ubo.params[1] = 0; - reflection_ubo.params[2] = rpi->probe_ptr->interior ? 1.0 : 0.0; - reflection_ubo.params[3] = rpi->probe_ptr->box_projection ? 1.0 : 0.0; - - if (rpi->probe_ptr->interior) { - Color ambient_linear = rpi->probe_ptr->interior_ambient.to_linear(); - reflection_ubo.ambient[0] = ambient_linear.r * rpi->probe_ptr->interior_ambient_energy; - reflection_ubo.ambient[1] = ambient_linear.g * rpi->probe_ptr->interior_ambient_energy; - reflection_ubo.ambient[2] = ambient_linear.b * rpi->probe_ptr->interior_ambient_energy; - reflection_ubo.ambient[3] = rpi->probe_ptr->interior_ambient_probe_contrib; - } else { - Color ambient_linear; - if (p_env) { - ambient_linear = p_env->ambient_color.to_linear(); - ambient_linear.r *= p_env->ambient_energy; - ambient_linear.g *= p_env->ambient_energy; - ambient_linear.b *= p_env->ambient_energy; - } - - reflection_ubo.ambient[0] = ambient_linear.r; - reflection_ubo.ambient[1] = ambient_linear.g; - reflection_ubo.ambient[2] = ambient_linear.b; - reflection_ubo.ambient[3] = 0; //not used in exterior mode, since it just blends with regular ambient light - } - - int cell_size = reflection_atlas->size / reflection_atlas->subdiv; - int x = (rpi->reflection_atlas_index % reflection_atlas->subdiv) * cell_size; - int y = (rpi->reflection_atlas_index / reflection_atlas->subdiv) * cell_size; - int width = cell_size; - int height = cell_size; - - reflection_ubo.atlas_clamp[0] = float(x) / reflection_atlas->size; - reflection_ubo.atlas_clamp[1] = float(y) / reflection_atlas->size; - reflection_ubo.atlas_clamp[2] = float(width) / reflection_atlas->size; - reflection_ubo.atlas_clamp[3] = float(height) / reflection_atlas->size; - - Transform proj = (p_camera_inverse_transform * rpi->transform).inverse(); - store_transform(proj, reflection_ubo.local_matrix); - - rpi->reflection_index = state.reflection_probe_count; - copymem(&state.reflection_array_tmp[rpi->reflection_index * sizeof(ReflectionProbeDataUBO)], &reflection_ubo, sizeof(ReflectionProbeDataUBO)); - state.reflection_probe_count++; - } - - if (state.reflection_probe_count) { - - glBindBuffer(GL_UNIFORM_BUFFER, state.reflection_array_ubo); - glBufferSubData(GL_UNIFORM_BUFFER, 0, state.reflection_probe_count * sizeof(ReflectionProbeDataUBO), state.reflection_array_tmp); - glBindBuffer(GL_UNIFORM_BUFFER, 0); - } - - glBindBufferBase(GL_UNIFORM_BUFFER, 6, state.reflection_array_ubo); -} - -void RasterizerSceneGLES3::_copy_screen(bool p_invalidate_color, bool p_invalidate_depth) { - -#ifndef GLES_OVER_GL - if (p_invalidate_color) { - - GLenum attachments[2] = { - GL_COLOR_ATTACHMENT0, - GL_DEPTH_ATTACHMENT - }; - - glInvalidateFramebuffer(GL_FRAMEBUFFER, p_invalidate_depth ? 2 : 1, attachments); - } -#endif - - glBindVertexArray(storage->resources.quadie_array); - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - glBindVertexArray(0); -} - -void RasterizerSceneGLES3::_copy_texture_to_front_buffer(GLuint p_texture) { - - //copy to front buffer - glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->fbo); - - glDepthMask(GL_FALSE); - glDisable(GL_DEPTH_TEST); - glDisable(GL_CULL_FACE); - glDisable(GL_BLEND); - glDepthFunc(GL_LEQUAL); - glColorMask(1, 1, 1, 1); - - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, p_texture); - - glViewport(0, 0, storage->frame.current_rt->width * 0.5, storage->frame.current_rt->height * 0.5); - - storage->shaders.copy.set_conditional(CopyShaderGLES3::DISABLE_ALPHA, true); - storage->shaders.copy.bind(); - - _copy_screen(); - - //turn off everything used - storage->shaders.copy.set_conditional(CopyShaderGLES3::LINEAR_TO_SRGB, false); - storage->shaders.copy.set_conditional(CopyShaderGLES3::DISABLE_ALPHA, false); -} - -void RasterizerSceneGLES3::_fill_render_list(InstanceBase **p_cull_result, int p_cull_count, bool p_depth_pass, bool p_shadow_pass) { - - current_geometry_index = 0; - current_material_index = 0; - state.used_sss = false; - state.used_screen_texture = false; - state.used_depth_texture = false; - - //fill list - - for (int i = 0; i < p_cull_count; i++) { - - InstanceBase *inst = p_cull_result[i]; - switch (inst->base_type) { - - case VS::INSTANCE_MESH: { - - RasterizerStorageGLES3::Mesh *mesh = storage->mesh_owner.getptr(inst->base); - ERR_CONTINUE(!mesh); - - int ssize = mesh->surfaces.size(); - - for (int j = 0; j < ssize; j++) { - - int mat_idx = inst->materials[j].is_valid() ? j : -1; - RasterizerStorageGLES3::Surface *s = mesh->surfaces[j]; - _add_geometry(s, inst, NULL, mat_idx, p_depth_pass, p_shadow_pass); - } - - //mesh->last_pass=frame; - - } break; - case VS::INSTANCE_MULTIMESH: { - - RasterizerStorageGLES3::MultiMesh *multi_mesh = storage->multimesh_owner.getptr(inst->base); - ERR_CONTINUE(!multi_mesh); - - if (multi_mesh->size == 0 || multi_mesh->visible_instances == 0) - continue; - - RasterizerStorageGLES3::Mesh *mesh = storage->mesh_owner.getptr(multi_mesh->mesh); - if (!mesh) - continue; //mesh not assigned - - int ssize = mesh->surfaces.size(); - - for (int j = 0; j < ssize; j++) { - - RasterizerStorageGLES3::Surface *s = mesh->surfaces[j]; - _add_geometry(s, inst, multi_mesh, -1, p_depth_pass, p_shadow_pass); - } - - } break; - case VS::INSTANCE_IMMEDIATE: { - - RasterizerStorageGLES3::Immediate *immediate = storage->immediate_owner.getptr(inst->base); - ERR_CONTINUE(!immediate); - - _add_geometry(immediate, inst, NULL, -1, p_depth_pass, p_shadow_pass); - - } break; - case VS::INSTANCE_PARTICLES: { - - RasterizerStorageGLES3::Particles *particles = storage->particles_owner.getptr(inst->base); - ERR_CONTINUE(!particles); - - for (int j = 0; j < particles->draw_passes.size(); j++) { - - RID pmesh = particles->draw_passes[j]; - if (!pmesh.is_valid()) - continue; - RasterizerStorageGLES3::Mesh *mesh = storage->mesh_owner.get(pmesh); - if (!mesh) - continue; //mesh not assigned - - int ssize = mesh->surfaces.size(); - - for (int k = 0; k < ssize; k++) { - - RasterizerStorageGLES3::Surface *s = mesh->surfaces[k]; - _add_geometry(s, inst, particles, -1, p_depth_pass, p_shadow_pass); - } - } - - } break; - default: { - } - } - } -} - -void RasterizerSceneGLES3::_blur_effect_buffer() { - - //blur diffuse into effect mipmaps using separatable convolution - //storage->shaders.copy.set_conditional(CopyShaderGLES3::GAUSSIAN_HORIZONTAL,true); - for (int i = 0; i < storage->frame.current_rt->effects.mip_maps[1].sizes.size(); i++) { - - int vp_w = storage->frame.current_rt->effects.mip_maps[1].sizes[i].width; - int vp_h = storage->frame.current_rt->effects.mip_maps[1].sizes[i].height; - glViewport(0, 0, vp_w, vp_h); - //horizontal pass - state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::GAUSSIAN_HORIZONTAL, true); - state.effect_blur_shader.bind(); - state.effect_blur_shader.set_uniform(EffectBlurShaderGLES3::PIXEL_SIZE, Vector2(1.0 / vp_w, 1.0 / vp_h)); - state.effect_blur_shader.set_uniform(EffectBlurShaderGLES3::LOD, float(i)); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->effects.mip_maps[0].color); //previous level, since mipmaps[0] starts one level bigger - glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->effects.mip_maps[1].sizes[i].fbo); - _copy_screen(true); - state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::GAUSSIAN_HORIZONTAL, false); - - //vertical pass - state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::GAUSSIAN_VERTICAL, true); - state.effect_blur_shader.bind(); - state.effect_blur_shader.set_uniform(EffectBlurShaderGLES3::PIXEL_SIZE, Vector2(1.0 / vp_w, 1.0 / vp_h)); - state.effect_blur_shader.set_uniform(EffectBlurShaderGLES3::LOD, float(i)); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->effects.mip_maps[1].color); - glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->effects.mip_maps[0].sizes[i + 1].fbo); //next level, since mipmaps[0] starts one level bigger - _copy_screen(true); - state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::GAUSSIAN_VERTICAL, false); - } -} - -void RasterizerSceneGLES3::_prepare_depth_texture() { - if (!state.prepared_depth_texture) { - //resolve depth buffer - glBindFramebuffer(GL_READ_FRAMEBUFFER, storage->frame.current_rt->buffers.fbo); - glReadBuffer(GL_COLOR_ATTACHMENT0); - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, storage->frame.current_rt->fbo); - glBlitFramebuffer(0, 0, storage->frame.current_rt->width, storage->frame.current_rt->height, 0, 0, storage->frame.current_rt->width, storage->frame.current_rt->height, GL_DEPTH_BUFFER_BIT, GL_NEAREST); - glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); - state.prepared_depth_texture = true; - } -} - -void RasterizerSceneGLES3::_bind_depth_texture() { - if (!state.bound_depth_texture) { - ERR_FAIL_COND(!state.prepared_depth_texture); - //bind depth for read - glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 8); - glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->depth); - state.bound_depth_texture = true; - } -} - -void RasterizerSceneGLES3::_render_mrts(Environment *env, const CameraMatrix &p_cam_projection) { - - glDepthMask(GL_FALSE); - glDisable(GL_DEPTH_TEST); - glDisable(GL_CULL_FACE); - glDisable(GL_BLEND); - - _prepare_depth_texture(); - - if (env->ssao_enabled || env->ssr_enabled) { - - //copy normal and roughness to effect buffer - glBindFramebuffer(GL_READ_FRAMEBUFFER, storage->frame.current_rt->buffers.fbo); - glReadBuffer(GL_COLOR_ATTACHMENT2); - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, storage->frame.current_rt->buffers.effect_fbo); - glBlitFramebuffer(0, 0, storage->frame.current_rt->width, storage->frame.current_rt->height, 0, 0, storage->frame.current_rt->width, storage->frame.current_rt->height, GL_COLOR_BUFFER_BIT, GL_NEAREST); - } - - if (env->ssao_enabled) { - //copy diffuse to front buffer - glBindFramebuffer(GL_READ_FRAMEBUFFER, storage->frame.current_rt->buffers.fbo); - glReadBuffer(GL_COLOR_ATTACHMENT0); - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, storage->frame.current_rt->fbo); - glBlitFramebuffer(0, 0, storage->frame.current_rt->width, storage->frame.current_rt->height, 0, 0, storage->frame.current_rt->width, storage->frame.current_rt->height, GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, GL_NEAREST); - - glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); - - //copy from depth, convert to linear - GLint ss[2]; - ss[0] = storage->frame.current_rt->width; - ss[1] = storage->frame.current_rt->height; - - for (int i = 0; i < storage->frame.current_rt->effects.ssao.depth_mipmap_fbos.size(); i++) { - - state.ssao_minify_shader.set_conditional(SsaoMinifyShaderGLES3::MINIFY_START, i == 0); - state.ssao_minify_shader.set_conditional(SsaoMinifyShaderGLES3::USE_ORTHOGONAL_PROJECTION, p_cam_projection.is_orthogonal()); - state.ssao_minify_shader.bind(); - state.ssao_minify_shader.set_uniform(SsaoMinifyShaderGLES3::CAMERA_Z_FAR, p_cam_projection.get_z_far()); - state.ssao_minify_shader.set_uniform(SsaoMinifyShaderGLES3::CAMERA_Z_NEAR, p_cam_projection.get_z_near()); - state.ssao_minify_shader.set_uniform(SsaoMinifyShaderGLES3::SOURCE_MIPMAP, MAX(0, i - 1)); - glUniform2iv(state.ssao_minify_shader.get_uniform(SsaoMinifyShaderGLES3::FROM_SIZE), 1, ss); - ss[0] >>= 1; - ss[1] >>= 1; - - glActiveTexture(GL_TEXTURE0); - if (i == 0) { - glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->depth); - } else { - glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->effects.ssao.linear_depth); - } - - glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->effects.ssao.depth_mipmap_fbos[i]); //copy to front first - glViewport(0, 0, ss[0], ss[1]); - - _copy_screen(true); - } - ss[0] = storage->frame.current_rt->width; - ss[1] = storage->frame.current_rt->height; - - glViewport(0, 0, ss[0], ss[1]); - - glEnable(GL_DEPTH_TEST); - glDepthFunc(GL_GREATER); - // do SSAO! - state.ssao_shader.set_conditional(SsaoShaderGLES3::ENABLE_RADIUS2, env->ssao_radius2 > 0.001); - state.ssao_shader.set_conditional(SsaoShaderGLES3::USE_ORTHOGONAL_PROJECTION, p_cam_projection.is_orthogonal()); - state.ssao_shader.set_conditional(SsaoShaderGLES3::SSAO_QUALITY_LOW, env->ssao_quality == VS::ENV_SSAO_QUALITY_LOW); - state.ssao_shader.set_conditional(SsaoShaderGLES3::SSAO_QUALITY_HIGH, env->ssao_quality == VS::ENV_SSAO_QUALITY_HIGH); - state.ssao_shader.bind(); - state.ssao_shader.set_uniform(SsaoShaderGLES3::CAMERA_Z_FAR, p_cam_projection.get_z_far()); - state.ssao_shader.set_uniform(SsaoShaderGLES3::CAMERA_Z_NEAR, p_cam_projection.get_z_near()); - glUniform2iv(state.ssao_shader.get_uniform(SsaoShaderGLES3::SCREEN_SIZE), 1, ss); - float radius = env->ssao_radius; - state.ssao_shader.set_uniform(SsaoShaderGLES3::RADIUS, radius); - float intensity = env->ssao_intensity; - state.ssao_shader.set_uniform(SsaoShaderGLES3::INTENSITY_DIV_R6, intensity / pow(radius, 6.0f)); - - if (env->ssao_radius2 > 0.001) { - - float radius2 = env->ssao_radius2; - state.ssao_shader.set_uniform(SsaoShaderGLES3::RADIUS2, radius2); - float intensity2 = env->ssao_intensity2; - state.ssao_shader.set_uniform(SsaoShaderGLES3::INTENSITY_DIV_R62, intensity2 / pow(radius2, 6.0f)); - } - - float proj_info[4] = { - -2.0f / (ss[0] * p_cam_projection.matrix[0][0]), - -2.0f / (ss[1] * p_cam_projection.matrix[1][1]), - (1.0f - p_cam_projection.matrix[0][2]) / p_cam_projection.matrix[0][0], - (1.0f + p_cam_projection.matrix[1][2]) / p_cam_projection.matrix[1][1] - }; - - glUniform4fv(state.ssao_shader.get_uniform(SsaoShaderGLES3::PROJ_INFO), 1, proj_info); - float pixels_per_meter = float(p_cam_projection.get_pixels_per_meter(ss[0])); - - state.ssao_shader.set_uniform(SsaoShaderGLES3::PROJ_SCALE, pixels_per_meter); - state.ssao_shader.set_uniform(SsaoShaderGLES3::BIAS, env->ssao_bias); - - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->depth); - glActiveTexture(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->effects.ssao.linear_depth); - glActiveTexture(GL_TEXTURE2); - glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->buffers.effect); - - glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->effects.ssao.blur_fbo[0]); //copy to front first - Color white(1, 1, 1, 1); - glClearBufferfv(GL_COLOR, 0, white.components); // specular - - _copy_screen(true); - - //do the batm, i mean blur - - state.ssao_blur_shader.bind(); - - if (env->ssao_filter) { - for (int i = 0; i < 2; i++) { - - state.ssao_blur_shader.set_uniform(SsaoBlurShaderGLES3::CAMERA_Z_FAR, p_cam_projection.get_z_far()); - state.ssao_blur_shader.set_uniform(SsaoBlurShaderGLES3::CAMERA_Z_NEAR, p_cam_projection.get_z_near()); - state.ssao_blur_shader.set_uniform(SsaoBlurShaderGLES3::EDGE_SHARPNESS, env->ssao_bilateral_sharpness); - state.ssao_blur_shader.set_uniform(SsaoBlurShaderGLES3::FILTER_SCALE, int(env->ssao_filter)); - - GLint axis[2] = { i, 1 - i }; - glUniform2iv(state.ssao_blur_shader.get_uniform(SsaoBlurShaderGLES3::AXIS), 1, axis); - glUniform2iv(state.ssao_blur_shader.get_uniform(SsaoBlurShaderGLES3::SCREEN_SIZE), 1, ss); - - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->effects.ssao.blur_red[i]); - glActiveTexture(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->depth); - glActiveTexture(GL_TEXTURE2); - glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->buffers.effect); - glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->effects.ssao.blur_fbo[1 - i]); - if (i == 0) { - glClearBufferfv(GL_COLOR, 0, white.components); // specular - } - _copy_screen(true); - } - } - - glDisable(GL_DEPTH_TEST); - glDepthFunc(GL_LEQUAL); - - // just copy diffuse while applying SSAO - - state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::SSAO_MERGE, true); - state.effect_blur_shader.bind(); - state.effect_blur_shader.set_uniform(EffectBlurShaderGLES3::SSAO_COLOR, env->ssao_color); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->color); //previous level, since mipmaps[0] starts one level bigger - glActiveTexture(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->effects.ssao.blur_red[0]); //previous level, since mipmaps[0] starts one level bigger - glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->effects.mip_maps[0].sizes[0].fbo); // copy to base level - _copy_screen(true); - state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::SSAO_MERGE, false); - - } else { - - //copy diffuse to effect buffer - glBindFramebuffer(GL_READ_FRAMEBUFFER, storage->frame.current_rt->buffers.fbo); - glReadBuffer(GL_COLOR_ATTACHMENT0); - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, storage->frame.current_rt->effects.mip_maps[0].sizes[0].fbo); - glBlitFramebuffer(0, 0, storage->frame.current_rt->width, storage->frame.current_rt->height, 0, 0, storage->frame.current_rt->width, storage->frame.current_rt->height, GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, GL_NEAREST); - - glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); - } - - if (state.used_sss) { //sss enabled - //copy diffuse while performing sss - - Plane p = p_cam_projection.xform4(Plane(1, 0, -1, 1)); - p.normal /= p.d; - float unit_size = p.normal.x; - - //copy normal and roughness to effect buffer - glBindFramebuffer(GL_READ_FRAMEBUFFER, storage->frame.current_rt->buffers.fbo); - glReadBuffer(GL_COLOR_ATTACHMENT3); - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, storage->frame.current_rt->effects.ssao.blur_fbo[0]); - glBlitFramebuffer(0, 0, storage->frame.current_rt->width, storage->frame.current_rt->height, 0, 0, storage->frame.current_rt->width, storage->frame.current_rt->height, GL_COLOR_BUFFER_BIT, GL_LINEAR); - - state.sss_shader.set_conditional(SubsurfScatteringShaderGLES3::USE_ORTHOGONAL_PROJECTION, p_cam_projection.is_orthogonal()); - state.sss_shader.set_conditional(SubsurfScatteringShaderGLES3::USE_11_SAMPLES, subsurface_scatter_quality == SSS_QUALITY_LOW); - state.sss_shader.set_conditional(SubsurfScatteringShaderGLES3::USE_17_SAMPLES, subsurface_scatter_quality == SSS_QUALITY_MEDIUM); - state.sss_shader.set_conditional(SubsurfScatteringShaderGLES3::USE_25_SAMPLES, subsurface_scatter_quality == SSS_QUALITY_HIGH); - state.sss_shader.set_conditional(SubsurfScatteringShaderGLES3::ENABLE_FOLLOW_SURFACE, subsurface_scatter_follow_surface); - state.sss_shader.set_conditional(SubsurfScatteringShaderGLES3::ENABLE_STRENGTH_WEIGHTING, subsurface_scatter_weight_samples); - state.sss_shader.bind(); - state.sss_shader.set_uniform(SubsurfScatteringShaderGLES3::MAX_RADIUS, subsurface_scatter_size); - state.sss_shader.set_uniform(SubsurfScatteringShaderGLES3::UNIT_SIZE, unit_size); - state.sss_shader.set_uniform(SubsurfScatteringShaderGLES3::CAMERA_Z_NEAR, p_cam_projection.get_z_near()); - state.sss_shader.set_uniform(SubsurfScatteringShaderGLES3::CAMERA_Z_FAR, p_cam_projection.get_z_far()); - state.sss_shader.set_uniform(SubsurfScatteringShaderGLES3::DIR, Vector2(1, 0)); - - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->effects.mip_maps[0].color); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); //disable filter (fixes bugs on AMD) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - - glActiveTexture(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->effects.ssao.blur_red[0]); - glActiveTexture(GL_TEXTURE2); - glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->depth); - //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE); - - glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->fbo); //copy to front first - - _copy_screen(true); - - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->color); - state.sss_shader.set_uniform(SubsurfScatteringShaderGLES3::DIR, Vector2(0, 1)); - glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->effects.mip_maps[0].sizes[0].fbo); // copy to base level - _copy_screen(true); - - glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->effects.mip_maps[0].color); //restore filter - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - } - - if (env->ssr_enabled) { - - //blur diffuse into effect mipmaps using separatable convolution - //storage->shaders.copy.set_conditional(CopyShaderGLES3::GAUSSIAN_HORIZONTAL,true); - _blur_effect_buffer(); - - //perform SSR - - state.ssr_shader.set_conditional(ScreenSpaceReflectionShaderGLES3::REFLECT_ROUGHNESS, env->ssr_roughness); - state.ssr_shader.set_conditional(ScreenSpaceReflectionShaderGLES3::USE_ORTHOGONAL_PROJECTION, p_cam_projection.is_orthogonal()); - - state.ssr_shader.bind(); - - int ssr_w = storage->frame.current_rt->effects.mip_maps[1].sizes[0].width; - int ssr_h = storage->frame.current_rt->effects.mip_maps[1].sizes[0].height; - - state.ssr_shader.set_uniform(ScreenSpaceReflectionShaderGLES3::PIXEL_SIZE, Vector2(1.0 / (ssr_w * 0.5), 1.0 / (ssr_h * 0.5))); - state.ssr_shader.set_uniform(ScreenSpaceReflectionShaderGLES3::CAMERA_Z_NEAR, p_cam_projection.get_z_near()); - state.ssr_shader.set_uniform(ScreenSpaceReflectionShaderGLES3::CAMERA_Z_FAR, p_cam_projection.get_z_far()); - state.ssr_shader.set_uniform(ScreenSpaceReflectionShaderGLES3::PROJECTION, p_cam_projection); - state.ssr_shader.set_uniform(ScreenSpaceReflectionShaderGLES3::INVERSE_PROJECTION, p_cam_projection.inverse()); - state.ssr_shader.set_uniform(ScreenSpaceReflectionShaderGLES3::VIEWPORT_SIZE, Size2(ssr_w, ssr_h)); - //state.ssr_shader.set_uniform(ScreenSpaceReflectionShaderGLES3::FRAME_INDEX,int(render_pass)); - state.ssr_shader.set_uniform(ScreenSpaceReflectionShaderGLES3::FILTER_MIPMAP_LEVELS, float(storage->frame.current_rt->effects.mip_maps[0].sizes.size())); - state.ssr_shader.set_uniform(ScreenSpaceReflectionShaderGLES3::NUM_STEPS, env->ssr_max_steps); - state.ssr_shader.set_uniform(ScreenSpaceReflectionShaderGLES3::DEPTH_TOLERANCE, env->ssr_depth_tolerance); - state.ssr_shader.set_uniform(ScreenSpaceReflectionShaderGLES3::DISTANCE_FADE, env->ssr_fade_out); - state.ssr_shader.set_uniform(ScreenSpaceReflectionShaderGLES3::CURVE_FADE_IN, env->ssr_fade_in); - - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->effects.mip_maps[0].color); - glActiveTexture(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->buffers.effect); - glActiveTexture(GL_TEXTURE2); - glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->depth); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE); - - glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->effects.mip_maps[1].sizes[0].fbo); - glViewport(0, 0, ssr_w, ssr_h); - - _copy_screen(true); - glViewport(0, 0, storage->frame.current_rt->width, storage->frame.current_rt->height); - } - - glBindFramebuffer(GL_READ_FRAMEBUFFER, storage->frame.current_rt->buffers.fbo); - glReadBuffer(GL_COLOR_ATTACHMENT1); - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, storage->frame.current_rt->fbo); - //glDrawBuffer(GL_COLOR_ATTACHMENT0); - glBlitFramebuffer(0, 0, storage->frame.current_rt->width, storage->frame.current_rt->height, 0, 0, storage->frame.current_rt->width, storage->frame.current_rt->height, GL_COLOR_BUFFER_BIT, GL_NEAREST); - glReadBuffer(GL_COLOR_ATTACHMENT0); - - glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); - - //copy reflection over diffuse, resolving SSR if needed - state.resolve_shader.set_conditional(ResolveShaderGLES3::USE_SSR, env->ssr_enabled); - state.resolve_shader.bind(); - state.resolve_shader.set_uniform(ResolveShaderGLES3::PIXEL_SIZE, Vector2(1.0 / storage->frame.current_rt->width, 1.0 / storage->frame.current_rt->height)); - - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->color); - if (env->ssr_enabled) { - glActiveTexture(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->effects.mip_maps[1].color); - } - - glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->effects.mip_maps[0].sizes[0].fbo); - glEnable(GL_BLEND); - glBlendEquation(GL_FUNC_ADD); - glBlendFunc(GL_ONE, GL_ONE); //use additive to accumulate one over the other - - _copy_screen(true); - - glDisable(GL_BLEND); //end additive - - if (state.used_screen_texture) { - _blur_effect_buffer(); - //restored framebuffer - glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->effects.mip_maps[0].sizes[0].fbo); - glViewport(0, 0, storage->frame.current_rt->width, storage->frame.current_rt->height); - } - - state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::SIMPLE_COPY, true); - state.effect_blur_shader.bind(); - state.effect_blur_shader.set_uniform(EffectBlurShaderGLES3::LOD, float(0)); - - { - GLuint db = GL_COLOR_ATTACHMENT0; - glDrawBuffers(1, &db); - } - - glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->buffers.fbo); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->effects.mip_maps[0].color); - - _copy_screen(true); - - state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::SIMPLE_COPY, false); -} - -void RasterizerSceneGLES3::_post_process(Environment *env, const CameraMatrix &p_cam_projection) { - - //copy to front buffer - - glDepthMask(GL_FALSE); - glDisable(GL_DEPTH_TEST); - glDisable(GL_CULL_FACE); - glDisable(GL_BLEND); - glDepthFunc(GL_LEQUAL); - glColorMask(1, 1, 1, 1); - - //turn off everything used - - //copy specular to front buffer - //copy diffuse to effect buffer - - if (storage->frame.current_rt->buffers.active) { - //transfer to effect buffer if using buffers, also resolve MSAA - glBindFramebuffer(GL_READ_FRAMEBUFFER, storage->frame.current_rt->buffers.fbo); - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, storage->frame.current_rt->effects.mip_maps[0].sizes[0].fbo); - glBlitFramebuffer(0, 0, storage->frame.current_rt->width, storage->frame.current_rt->height, 0, 0, storage->frame.current_rt->width, storage->frame.current_rt->height, GL_COLOR_BUFFER_BIT, GL_NEAREST); - - glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); - } - - if (!env || storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT] || storage->frame.current_rt->width < 4 || storage->frame.current_rt->height < 4) { //no post process on small render targets - //no environment or transparent render, simply return and convert to SRGB - if (storage->frame.current_rt->external.fbo != 0) { - glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->external.fbo); - } else { - glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->fbo); - } - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->effects.mip_maps[0].color); - storage->shaders.copy.set_conditional(CopyShaderGLES3::LINEAR_TO_SRGB, !storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_KEEP_3D_LINEAR]); - storage->shaders.copy.set_conditional(CopyShaderGLES3::V_FLIP, storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_VFLIP]); - storage->shaders.copy.set_conditional(CopyShaderGLES3::DISABLE_ALPHA, !storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]); - storage->shaders.copy.bind(); - - _copy_screen(true); - - storage->shaders.copy.set_conditional(CopyShaderGLES3::LINEAR_TO_SRGB, false); - storage->shaders.copy.set_conditional(CopyShaderGLES3::DISABLE_ALPHA, false); //compute luminance - storage->shaders.copy.set_conditional(CopyShaderGLES3::V_FLIP, false); - - return; - } - - //order of operation - //1) DOF Blur (first blur, then copy to buffer applying the blur) - //2) Motion Blur - //3) Bloom - //4) Tonemap - //5) Adjustments - - GLuint composite_from = storage->frame.current_rt->effects.mip_maps[0].color; - - if (env->dof_blur_far_enabled) { - - //blur diffuse into effect mipmaps using separatable convolution - //storage->shaders.copy.set_conditional(CopyShaderGLES3::GAUSSIAN_HORIZONTAL,true); - - int vp_h = storage->frame.current_rt->height; - int vp_w = storage->frame.current_rt->width; - - state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::USE_ORTHOGONAL_PROJECTION, p_cam_projection.is_orthogonal()); - state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::DOF_FAR_BLUR, true); - state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::DOF_QUALITY_LOW, env->dof_blur_far_quality == VS::ENV_DOF_BLUR_QUALITY_LOW); - state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::DOF_QUALITY_MEDIUM, env->dof_blur_far_quality == VS::ENV_DOF_BLUR_QUALITY_MEDIUM); - state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::DOF_QUALITY_HIGH, env->dof_blur_far_quality == VS::ENV_DOF_BLUR_QUALITY_HIGH); - - state.effect_blur_shader.bind(); - int qsteps[3] = { 4, 10, 20 }; - - float radius = (env->dof_blur_far_amount * env->dof_blur_far_amount) / qsteps[env->dof_blur_far_quality]; - - state.effect_blur_shader.set_uniform(EffectBlurShaderGLES3::DOF_BEGIN, env->dof_blur_far_distance); - state.effect_blur_shader.set_uniform(EffectBlurShaderGLES3::DOF_END, env->dof_blur_far_distance + env->dof_blur_far_transition); - state.effect_blur_shader.set_uniform(EffectBlurShaderGLES3::DOF_DIR, Vector2(1, 0)); - state.effect_blur_shader.set_uniform(EffectBlurShaderGLES3::DOF_RADIUS, radius); - state.effect_blur_shader.set_uniform(EffectBlurShaderGLES3::PIXEL_SIZE, Vector2(1.0 / vp_w, 1.0 / vp_h)); - state.effect_blur_shader.set_uniform(EffectBlurShaderGLES3::CAMERA_Z_NEAR, p_cam_projection.get_z_near()); - state.effect_blur_shader.set_uniform(EffectBlurShaderGLES3::CAMERA_Z_FAR, p_cam_projection.get_z_far()); - - glActiveTexture(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->depth); - - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, composite_from); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->fbo); //copy to front first - - _copy_screen(true); - - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->color); - state.effect_blur_shader.set_uniform(EffectBlurShaderGLES3::DOF_DIR, Vector2(0, 1)); - glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->effects.mip_maps[0].sizes[0].fbo); // copy to base level - _copy_screen(); - - state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::DOF_FAR_BLUR, false); - state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::DOF_QUALITY_LOW, false); - state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::DOF_QUALITY_MEDIUM, false); - state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::DOF_QUALITY_HIGH, false); - state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::USE_ORTHOGONAL_PROJECTION, false); - - composite_from = storage->frame.current_rt->effects.mip_maps[0].color; - } - - if (env->dof_blur_near_enabled) { - - //blur diffuse into effect mipmaps using separatable convolution - //storage->shaders.copy.set_conditional(CopyShaderGLES3::GAUSSIAN_HORIZONTAL,true); - - int vp_h = storage->frame.current_rt->height; - int vp_w = storage->frame.current_rt->width; - - state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::USE_ORTHOGONAL_PROJECTION, p_cam_projection.is_orthogonal()); - state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::DOF_NEAR_BLUR, true); - state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::DOF_NEAR_FIRST_TAP, true); - - state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::DOF_QUALITY_LOW, env->dof_blur_near_quality == VS::ENV_DOF_BLUR_QUALITY_LOW); - state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::DOF_QUALITY_MEDIUM, env->dof_blur_near_quality == VS::ENV_DOF_BLUR_QUALITY_MEDIUM); - state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::DOF_QUALITY_HIGH, env->dof_blur_near_quality == VS::ENV_DOF_BLUR_QUALITY_HIGH); - - state.effect_blur_shader.bind(); - int qsteps[3] = { 4, 10, 20 }; - - float radius = (env->dof_blur_near_amount * env->dof_blur_near_amount) / qsteps[env->dof_blur_near_quality]; - - state.effect_blur_shader.set_uniform(EffectBlurShaderGLES3::DOF_BEGIN, env->dof_blur_near_distance); - state.effect_blur_shader.set_uniform(EffectBlurShaderGLES3::DOF_END, env->dof_blur_near_distance - env->dof_blur_near_transition); - state.effect_blur_shader.set_uniform(EffectBlurShaderGLES3::DOF_DIR, Vector2(1, 0)); - state.effect_blur_shader.set_uniform(EffectBlurShaderGLES3::DOF_RADIUS, radius); - state.effect_blur_shader.set_uniform(EffectBlurShaderGLES3::PIXEL_SIZE, Vector2(1.0 / vp_w, 1.0 / vp_h)); - state.effect_blur_shader.set_uniform(EffectBlurShaderGLES3::CAMERA_Z_NEAR, p_cam_projection.get_z_near()); - state.effect_blur_shader.set_uniform(EffectBlurShaderGLES3::CAMERA_Z_FAR, p_cam_projection.get_z_far()); - - glActiveTexture(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->depth); - - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, composite_from); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->fbo); //copy to front first - - _copy_screen(); - //manually do the blend if this is the first operation resolving from the diffuse buffer - state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::DOF_NEAR_BLUR_MERGE, composite_from == storage->frame.current_rt->buffers.diffuse); - state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::DOF_NEAR_FIRST_TAP, false); - state.effect_blur_shader.bind(); - - state.effect_blur_shader.set_uniform(EffectBlurShaderGLES3::DOF_BEGIN, env->dof_blur_near_distance); - state.effect_blur_shader.set_uniform(EffectBlurShaderGLES3::DOF_END, env->dof_blur_near_distance - env->dof_blur_near_transition); - state.effect_blur_shader.set_uniform(EffectBlurShaderGLES3::DOF_DIR, Vector2(0, 1)); - state.effect_blur_shader.set_uniform(EffectBlurShaderGLES3::DOF_RADIUS, radius); - state.effect_blur_shader.set_uniform(EffectBlurShaderGLES3::PIXEL_SIZE, Vector2(1.0 / vp_w, 1.0 / vp_h)); - state.effect_blur_shader.set_uniform(EffectBlurShaderGLES3::CAMERA_Z_NEAR, p_cam_projection.get_z_near()); - state.effect_blur_shader.set_uniform(EffectBlurShaderGLES3::CAMERA_Z_FAR, p_cam_projection.get_z_far()); - - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->color); - - glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->effects.mip_maps[0].sizes[0].fbo); // copy to base level - - if (composite_from != storage->frame.current_rt->buffers.diffuse) { - - glEnable(GL_BLEND); - glBlendEquation(GL_FUNC_ADD); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - } else { - glActiveTexture(GL_TEXTURE2); - glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->buffers.diffuse); - } - - _copy_screen(true); - - if (composite_from != storage->frame.current_rt->buffers.diffuse) { - - glDisable(GL_BLEND); - } - - state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::DOF_NEAR_BLUR, false); - state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::DOF_NEAR_FIRST_TAP, false); - state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::DOF_NEAR_BLUR_MERGE, false); - state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::DOF_QUALITY_LOW, false); - state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::DOF_QUALITY_MEDIUM, false); - state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::DOF_QUALITY_HIGH, false); - state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::USE_ORTHOGONAL_PROJECTION, false); - - composite_from = storage->frame.current_rt->effects.mip_maps[0].color; - } - - if (env->dof_blur_near_enabled || env->dof_blur_far_enabled) { - //these needed to disable filtering, reenamble - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->effects.mip_maps[0].color); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - } - - if (env->auto_exposure) { - - //compute auto exposure - //first step, copy from image to luminance buffer - state.exposure_shader.set_conditional(ExposureShaderGLES3::EXPOSURE_BEGIN, true); - state.exposure_shader.bind(); - int ss[2] = { - storage->frame.current_rt->width, - storage->frame.current_rt->height, - }; - int ds[2] = { - exposure_shrink_size, - exposure_shrink_size, - }; - - glUniform2iv(state.exposure_shader.get_uniform(ExposureShaderGLES3::SOURCE_RENDER_SIZE), 1, ss); - glUniform2iv(state.exposure_shader.get_uniform(ExposureShaderGLES3::TARGET_SIZE), 1, ds); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, composite_from); - - glBindFramebuffer(GL_FRAMEBUFFER, exposure_shrink[0].fbo); - glViewport(0, 0, exposure_shrink_size, exposure_shrink_size); - - _copy_screen(true); - - //second step, shrink to 2x2 pixels - state.exposure_shader.set_conditional(ExposureShaderGLES3::EXPOSURE_BEGIN, false); - state.exposure_shader.bind(); - //shrink from second to previous to last level - - int s_size = exposure_shrink_size / 3; - for (int i = 1; i < exposure_shrink.size() - 1; i++) { - - glBindFramebuffer(GL_FRAMEBUFFER, exposure_shrink[i].fbo); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, exposure_shrink[i - 1].color); - - _copy_screen(); - - glViewport(0, 0, s_size, s_size); - - s_size /= 3; - } - //third step, shrink to 1x1 pixel taking in consideration the previous exposure - state.exposure_shader.set_conditional(ExposureShaderGLES3::EXPOSURE_END, true); - - uint64_t tick = OS::get_singleton()->get_ticks_usec(); - uint64_t tick_diff = storage->frame.current_rt->last_exposure_tick == 0 ? 0 : tick - storage->frame.current_rt->last_exposure_tick; - storage->frame.current_rt->last_exposure_tick = tick; - - if (tick_diff == 0 || tick_diff > 1000000) { - state.exposure_shader.set_conditional(ExposureShaderGLES3::EXPOSURE_FORCE_SET, true); - } - - state.exposure_shader.bind(); - - glBindFramebuffer(GL_FRAMEBUFFER, exposure_shrink[exposure_shrink.size() - 1].fbo); - glViewport(0, 0, 1, 1); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, exposure_shrink[exposure_shrink.size() - 2].color); - glActiveTexture(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->exposure.color); //read from previous - - state.exposure_shader.set_uniform(ExposureShaderGLES3::EXPOSURE_ADJUST, env->auto_exposure_speed * (tick_diff / 1000000.0)); - state.exposure_shader.set_uniform(ExposureShaderGLES3::MAX_LUMINANCE, env->auto_exposure_max); - state.exposure_shader.set_uniform(ExposureShaderGLES3::MIN_LUMINANCE, env->auto_exposure_min); - - _copy_screen(true); - - state.exposure_shader.set_conditional(ExposureShaderGLES3::EXPOSURE_FORCE_SET, false); - state.exposure_shader.set_conditional(ExposureShaderGLES3::EXPOSURE_END, false); - - //last step, swap with the framebuffer exposure, so the right exposure is kept int he framebuffer - SWAP(exposure_shrink.write[exposure_shrink.size() - 1].fbo, storage->frame.current_rt->exposure.fbo); - SWAP(exposure_shrink.write[exposure_shrink.size() - 1].color, storage->frame.current_rt->exposure.color); - - glViewport(0, 0, storage->frame.current_rt->width, storage->frame.current_rt->height); - - VisualServerRaster::redraw_request(); //if using auto exposure, redraw must happen - } - - int max_glow_level = -1; - int glow_mask = 0; - - if (env->glow_enabled) { - - for (int i = 0; i < VS::MAX_GLOW_LEVELS; i++) { - if (env->glow_levels & (1 << i)) { - - if (i >= storage->frame.current_rt->effects.mip_maps[1].sizes.size()) { - max_glow_level = storage->frame.current_rt->effects.mip_maps[1].sizes.size() - 1; - glow_mask |= 1 << max_glow_level; - - } else { - max_glow_level = i; - glow_mask |= (1 << i); - } - } - } - - //blur diffuse into effect mipmaps using separatable convolution - //storage->shaders.copy.set_conditional(CopyShaderGLES3::GAUSSIAN_HORIZONTAL,true); - - for (int i = 0; i < (max_glow_level + 1); i++) { - - int vp_w = storage->frame.current_rt->effects.mip_maps[1].sizes[i].width; - int vp_h = storage->frame.current_rt->effects.mip_maps[1].sizes[i].height; - glViewport(0, 0, vp_w, vp_h); - //horizontal pass - if (i == 0) { - state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::GLOW_FIRST_PASS, true); - state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::GLOW_USE_AUTO_EXPOSURE, env->auto_exposure); - } - - state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::GLOW_GAUSSIAN_HORIZONTAL, true); - state.effect_blur_shader.bind(); - state.effect_blur_shader.set_uniform(EffectBlurShaderGLES3::PIXEL_SIZE, Vector2(1.0 / vp_w, 1.0 / vp_h)); - state.effect_blur_shader.set_uniform(EffectBlurShaderGLES3::LOD, float(i)); - state.effect_blur_shader.set_uniform(EffectBlurShaderGLES3::GLOW_STRENGTH, env->glow_strength); - state.effect_blur_shader.set_uniform(EffectBlurShaderGLES3::LUMINANCE_CAP, env->glow_hdr_luminance_cap); - - glActiveTexture(GL_TEXTURE0); - if (i == 0) { - glBindTexture(GL_TEXTURE_2D, composite_from); - - state.effect_blur_shader.set_uniform(EffectBlurShaderGLES3::EXPOSURE, env->tone_mapper_exposure); - if (env->auto_exposure) { - state.effect_blur_shader.set_uniform(EffectBlurShaderGLES3::AUTO_EXPOSURE_GREY, env->auto_exposure_grey); - } - - glActiveTexture(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->exposure.color); - - state.effect_blur_shader.set_uniform(EffectBlurShaderGLES3::GLOW_BLOOM, env->glow_bloom); - state.effect_blur_shader.set_uniform(EffectBlurShaderGLES3::GLOW_HDR_THRESHOLD, env->glow_hdr_bleed_threshold); - state.effect_blur_shader.set_uniform(EffectBlurShaderGLES3::GLOW_HDR_SCALE, env->glow_hdr_bleed_scale); - - } else { - glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->effects.mip_maps[0].color); //previous level, since mipmaps[0] starts one level bigger - } - glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->effects.mip_maps[1].sizes[i].fbo); - _copy_screen(true); - state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::GLOW_GAUSSIAN_HORIZONTAL, false); - state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::GLOW_FIRST_PASS, false); - state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::GLOW_USE_AUTO_EXPOSURE, false); - - //vertical pass - state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::GLOW_GAUSSIAN_VERTICAL, true); - state.effect_blur_shader.bind(); - state.effect_blur_shader.set_uniform(EffectBlurShaderGLES3::PIXEL_SIZE, Vector2(1.0 / vp_w, 1.0 / vp_h)); - state.effect_blur_shader.set_uniform(EffectBlurShaderGLES3::LOD, float(i)); - state.effect_blur_shader.set_uniform(EffectBlurShaderGLES3::GLOW_STRENGTH, env->glow_strength); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->effects.mip_maps[1].color); - glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->effects.mip_maps[0].sizes[i + 1].fbo); //next level, since mipmaps[0] starts one level bigger - _copy_screen(); - state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::GLOW_GAUSSIAN_VERTICAL, false); - } - - glViewport(0, 0, storage->frame.current_rt->width, storage->frame.current_rt->height); - } - - if (storage->frame.current_rt->external.fbo != 0) { - glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->external.fbo); - } else { - glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->fbo); - } - - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, composite_from); - - state.tonemap_shader.set_conditional(TonemapShaderGLES3::USE_FILMIC_TONEMAPPER, env->tone_mapper == VS::ENV_TONE_MAPPER_FILMIC); - state.tonemap_shader.set_conditional(TonemapShaderGLES3::USE_ACES_TONEMAPPER, env->tone_mapper == VS::ENV_TONE_MAPPER_ACES); - state.tonemap_shader.set_conditional(TonemapShaderGLES3::USE_REINHARD_TONEMAPPER, env->tone_mapper == VS::ENV_TONE_MAPPER_REINHARD); - state.tonemap_shader.set_conditional(TonemapShaderGLES3::KEEP_3D_LINEAR, storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_KEEP_3D_LINEAR]); - - state.tonemap_shader.set_conditional(TonemapShaderGLES3::USE_AUTO_EXPOSURE, env->auto_exposure); - state.tonemap_shader.set_conditional(TonemapShaderGLES3::USE_GLOW_FILTER_BICUBIC, env->glow_bicubic_upscale); - - if (max_glow_level >= 0) { - - for (int i = 0; i < (max_glow_level + 1); i++) { - - if (glow_mask & (1 << i)) { - if (i == 0) { - state.tonemap_shader.set_conditional(TonemapShaderGLES3::USE_GLOW_LEVEL1, true); - } - if (i == 1) { - state.tonemap_shader.set_conditional(TonemapShaderGLES3::USE_GLOW_LEVEL2, true); - } - if (i == 2) { - state.tonemap_shader.set_conditional(TonemapShaderGLES3::USE_GLOW_LEVEL3, true); - } - if (i == 3) { - state.tonemap_shader.set_conditional(TonemapShaderGLES3::USE_GLOW_LEVEL4, true); - } - if (i == 4) { - state.tonemap_shader.set_conditional(TonemapShaderGLES3::USE_GLOW_LEVEL5, true); - } - if (i == 5) { - state.tonemap_shader.set_conditional(TonemapShaderGLES3::USE_GLOW_LEVEL6, true); - } - if (i == 6) { - state.tonemap_shader.set_conditional(TonemapShaderGLES3::USE_GLOW_LEVEL7, true); - } - } - } - - state.tonemap_shader.set_conditional(TonemapShaderGLES3::USE_GLOW_SCREEN, env->glow_blend_mode == VS::GLOW_BLEND_MODE_SCREEN); - state.tonemap_shader.set_conditional(TonemapShaderGLES3::USE_GLOW_SOFTLIGHT, env->glow_blend_mode == VS::GLOW_BLEND_MODE_SOFTLIGHT); - state.tonemap_shader.set_conditional(TonemapShaderGLES3::USE_GLOW_REPLACE, env->glow_blend_mode == VS::GLOW_BLEND_MODE_REPLACE); - glActiveTexture(GL_TEXTURE2); - glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->effects.mip_maps[0].color); - } - - if (env->adjustments_enabled) { - - state.tonemap_shader.set_conditional(TonemapShaderGLES3::USE_BCS, true); - RasterizerStorageGLES3::Texture *tex = storage->texture_owner.getornull(env->color_correction); - if (tex) { - state.tonemap_shader.set_conditional(TonemapShaderGLES3::USE_COLOR_CORRECTION, true); - glActiveTexture(GL_TEXTURE3); - glBindTexture(tex->target, tex->tex_id); - } - } - - state.tonemap_shader.set_conditional(TonemapShaderGLES3::V_FLIP, storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_VFLIP]); - state.tonemap_shader.bind(); - - state.tonemap_shader.set_uniform(TonemapShaderGLES3::EXPOSURE, env->tone_mapper_exposure); - state.tonemap_shader.set_uniform(TonemapShaderGLES3::WHITE, env->tone_mapper_exposure_white); - - if (max_glow_level >= 0) { - - state.tonemap_shader.set_uniform(TonemapShaderGLES3::GLOW_INTENSITY, env->glow_intensity); - int ss[2] = { - storage->frame.current_rt->width, - storage->frame.current_rt->height, - }; - glUniform2iv(state.tonemap_shader.get_uniform(TonemapShaderGLES3::GLOW_TEXTURE_SIZE), 1, ss); - } - - if (env->auto_exposure) { - - glActiveTexture(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->exposure.color); - state.tonemap_shader.set_uniform(TonemapShaderGLES3::AUTO_EXPOSURE_GREY, env->auto_exposure_grey); - } - - if (env->adjustments_enabled) { - - state.tonemap_shader.set_uniform(TonemapShaderGLES3::BCS, Vector3(env->adjustments_brightness, env->adjustments_contrast, env->adjustments_saturation)); - } - - _copy_screen(true, true); - - //turn off everything used - state.tonemap_shader.set_conditional(TonemapShaderGLES3::USE_AUTO_EXPOSURE, false); - state.tonemap_shader.set_conditional(TonemapShaderGLES3::USE_FILMIC_TONEMAPPER, false); - state.tonemap_shader.set_conditional(TonemapShaderGLES3::USE_ACES_TONEMAPPER, false); - state.tonemap_shader.set_conditional(TonemapShaderGLES3::USE_REINHARD_TONEMAPPER, false); - state.tonemap_shader.set_conditional(TonemapShaderGLES3::USE_GLOW_LEVEL1, false); - state.tonemap_shader.set_conditional(TonemapShaderGLES3::USE_GLOW_LEVEL2, false); - state.tonemap_shader.set_conditional(TonemapShaderGLES3::USE_GLOW_LEVEL3, false); - state.tonemap_shader.set_conditional(TonemapShaderGLES3::USE_GLOW_LEVEL4, false); - state.tonemap_shader.set_conditional(TonemapShaderGLES3::USE_GLOW_LEVEL5, false); - state.tonemap_shader.set_conditional(TonemapShaderGLES3::USE_GLOW_LEVEL6, false); - state.tonemap_shader.set_conditional(TonemapShaderGLES3::USE_GLOW_LEVEL7, false); - state.tonemap_shader.set_conditional(TonemapShaderGLES3::USE_GLOW_REPLACE, false); - state.tonemap_shader.set_conditional(TonemapShaderGLES3::USE_GLOW_SCREEN, false); - state.tonemap_shader.set_conditional(TonemapShaderGLES3::USE_GLOW_SOFTLIGHT, false); - state.tonemap_shader.set_conditional(TonemapShaderGLES3::USE_GLOW_FILTER_BICUBIC, false); - state.tonemap_shader.set_conditional(TonemapShaderGLES3::USE_BCS, false); - state.tonemap_shader.set_conditional(TonemapShaderGLES3::USE_COLOR_CORRECTION, false); - state.tonemap_shader.set_conditional(TonemapShaderGLES3::V_FLIP, false); -} - -void RasterizerSceneGLES3::render_scene(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID p_environment, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass) { - - //first of all, make a new render pass - render_pass++; - - //fill up ubo - - storage->info.render.object_count += p_cull_count; - - Environment *env = environment_owner.getornull(p_environment); - ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_shadow_atlas); - ReflectionAtlas *reflection_atlas = reflection_atlas_owner.getornull(p_reflection_atlas); - - bool use_shadows = shadow_atlas && shadow_atlas->size; - - state.scene_shader.set_conditional(SceneShaderGLES3::USE_SHADOW, use_shadows); - - if (use_shadows) { - glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 5); - glBindTexture(GL_TEXTURE_2D, shadow_atlas->depth); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LESS); - state.ubo_data.shadow_atlas_pixel_size[0] = 1.0 / shadow_atlas->size; - state.ubo_data.shadow_atlas_pixel_size[1] = 1.0 / shadow_atlas->size; - } - - if (reflection_atlas && reflection_atlas->size) { - glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 3); - glBindTexture(GL_TEXTURE_2D, reflection_atlas->color); - } - - if (p_reflection_probe.is_valid()) { - state.ubo_data.reflection_multiplier = 0.0; - } else { - state.ubo_data.reflection_multiplier = 1.0; - } - - state.ubo_data.subsurface_scatter_width = subsurface_scatter_size; - - state.ubo_data.z_offset = 0; - state.ubo_data.z_slope_scale = 0; - state.ubo_data.shadow_dual_paraboloid_render_side = 0; - state.ubo_data.shadow_dual_paraboloid_render_zfar = 0; - state.ubo_data.opaque_prepass_threshold = 0.99; - - if (storage->frame.current_rt) { - int viewport_width_pixels = storage->frame.current_rt->width; - int viewport_height_pixels = storage->frame.current_rt->height; - - state.ubo_data.viewport_size[0] = viewport_width_pixels; - state.ubo_data.viewport_size[1] = viewport_height_pixels; - - state.ubo_data.screen_pixel_size[0] = 1.0 / viewport_width_pixels; - state.ubo_data.screen_pixel_size[1] = 1.0 / viewport_height_pixels; - } - - _setup_environment(env, p_cam_projection, p_cam_transform, p_reflection_probe.is_valid()); - - bool fb_cleared = false; - - glDepthFunc(GL_LEQUAL); - - state.used_contact_shadows = false; - state.prepared_depth_texture = false; - state.bound_depth_texture = false; - - for (int i = 0; i < p_light_cull_count; i++) { - - ERR_BREAK(i >= render_list.max_lights); - - LightInstance *li = light_instance_owner.getptr(p_light_cull_result[i]); - if (li->light_ptr->param[VS::LIGHT_PARAM_CONTACT_SHADOW_SIZE] > CMP_EPSILON) { - state.used_contact_shadows = true; - } - } - - // Do depth prepass if it's explicitly enabled - bool use_depth_prepass = storage->config.use_depth_prepass; - - // If contact shadows are used then we need to do depth prepass even if it's otherwise disabled - use_depth_prepass = use_depth_prepass || state.used_contact_shadows; - - // Never do depth prepass if effects are disabled or if we render overdraws - use_depth_prepass = use_depth_prepass && storage->frame.current_rt && !storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_NO_3D_EFFECTS]; - use_depth_prepass = use_depth_prepass && state.debug_draw != VS::VIEWPORT_DEBUG_DRAW_OVERDRAW; - - if (use_depth_prepass) { - //pre z pass - - glDisable(GL_BLEND); - glDepthMask(GL_TRUE); - glEnable(GL_DEPTH_TEST); - glDisable(GL_SCISSOR_TEST); - glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->buffers.fbo); - glDrawBuffers(0, NULL); - - glViewport(0, 0, storage->frame.current_rt->width, storage->frame.current_rt->height); - - glColorMask(0, 0, 0, 0); - glClearDepth(1.0f); - glClear(GL_DEPTH_BUFFER_BIT); - - render_list.clear(); - _fill_render_list(p_cull_result, p_cull_count, true, false); - render_list.sort_by_key(false); - state.scene_shader.set_conditional(SceneShaderGLES3::RENDER_DEPTH, true); - _render_list(render_list.elements, render_list.element_count, p_cam_transform, p_cam_projection, NULL, false, false, true, false, false); - state.scene_shader.set_conditional(SceneShaderGLES3::RENDER_DEPTH, false); - - glColorMask(1, 1, 1, 1); - - if (state.used_contact_shadows) { - - _prepare_depth_texture(); - _bind_depth_texture(); - } - - fb_cleared = true; - render_pass++; - state.used_depth_prepass = true; - } else { - state.used_depth_prepass = false; - } - - _setup_lights(p_light_cull_result, p_light_cull_count, p_cam_transform.affine_inverse(), p_cam_projection, p_shadow_atlas); - _setup_reflections(p_reflection_probe_cull_result, p_reflection_probe_cull_count, p_cam_transform.affine_inverse(), p_cam_projection, p_reflection_atlas, env); - - bool use_mrt = false; - - render_list.clear(); - _fill_render_list(p_cull_result, p_cull_count, false, false); - // - - glEnable(GL_BLEND); - glDepthMask(GL_TRUE); - glEnable(GL_DEPTH_TEST); - glDisable(GL_SCISSOR_TEST); - - //rendering to a probe cubemap side - ReflectionProbeInstance *probe = reflection_probe_instance_owner.getornull(p_reflection_probe); - GLuint current_fbo; - - if (probe) { - - ReflectionAtlas *ref_atlas = reflection_atlas_owner.getptr(probe->atlas); - ERR_FAIL_COND(!ref_atlas); - - int target_size = ref_atlas->size / ref_atlas->subdiv; - - int cubemap_index = reflection_cubemaps.size() - 1; - - for (int i = reflection_cubemaps.size() - 1; i >= 0; i--) { - //find appropriate cubemap to render to - if (reflection_cubemaps[i].size > target_size * 2) - break; - - cubemap_index = i; - } - - current_fbo = reflection_cubemaps[cubemap_index].fbo_id[p_reflection_probe_pass]; - use_mrt = false; - state.scene_shader.set_conditional(SceneShaderGLES3::USE_MULTIPLE_RENDER_TARGETS, false); - - glViewport(0, 0, reflection_cubemaps[cubemap_index].size, reflection_cubemaps[cubemap_index].size); - glBindFramebuffer(GL_FRAMEBUFFER, current_fbo); - - } else { - - use_mrt = env && (state.used_sss || env->ssao_enabled || env->ssr_enabled || env->dof_blur_far_enabled || env->dof_blur_near_enabled); //only enable MRT rendering if any of these is enabled - //effects disabled and transparency also prevent using MRTs - use_mrt = use_mrt && !storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]; - use_mrt = use_mrt && !storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_NO_3D_EFFECTS]; - use_mrt = use_mrt && state.debug_draw != VS::VIEWPORT_DEBUG_DRAW_OVERDRAW; - use_mrt = use_mrt && (env->bg_mode != VS::ENV_BG_KEEP && env->bg_mode != VS::ENV_BG_CANVAS); - - glViewport(0, 0, storage->frame.current_rt->width, storage->frame.current_rt->height); - - if (use_mrt) { - - current_fbo = storage->frame.current_rt->buffers.fbo; - - glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->buffers.fbo); - state.scene_shader.set_conditional(SceneShaderGLES3::USE_MULTIPLE_RENDER_TARGETS, true); - - Vector<GLenum> draw_buffers; - draw_buffers.push_back(GL_COLOR_ATTACHMENT0); - draw_buffers.push_back(GL_COLOR_ATTACHMENT1); - draw_buffers.push_back(GL_COLOR_ATTACHMENT2); - if (state.used_sss) { - draw_buffers.push_back(GL_COLOR_ATTACHMENT3); - } - glDrawBuffers(draw_buffers.size(), draw_buffers.ptr()); - - Color black(0, 0, 0, 0); - glClearBufferfv(GL_COLOR, 1, black.components); // specular - glClearBufferfv(GL_COLOR, 2, black.components); // normal metal rough - if (state.used_sss) { - glClearBufferfv(GL_COLOR, 3, black.components); // normal metal rough - } - - } else { - - if (storage->frame.current_rt->buffers.active) { - current_fbo = storage->frame.current_rt->buffers.fbo; - } else { - if (storage->frame.current_rt->effects.mip_maps[0].sizes.size() == 0) { - ERR_PRINT_ONCE("Can't use canvas background mode in a render target configured without sampling"); - return; - } - current_fbo = storage->frame.current_rt->effects.mip_maps[0].sizes[0].fbo; - } - - glBindFramebuffer(GL_FRAMEBUFFER, current_fbo); - state.scene_shader.set_conditional(SceneShaderGLES3::USE_MULTIPLE_RENDER_TARGETS, false); - - Vector<GLenum> draw_buffers; - draw_buffers.push_back(GL_COLOR_ATTACHMENT0); - glDrawBuffers(draw_buffers.size(), draw_buffers.ptr()); - } - } - - if (!fb_cleared) { - glClearDepth(1.0f); - glClear(GL_DEPTH_BUFFER_BIT); - } - - Color clear_color(0, 0, 0, 0); - - RasterizerStorageGLES3::Sky *sky = NULL; - Ref<CameraFeed> feed; - - if (state.debug_draw == VS::VIEWPORT_DEBUG_DRAW_OVERDRAW) { - clear_color = Color(0, 0, 0, 0); - storage->frame.clear_request = false; - } else if (!probe && storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]) { - clear_color = Color(0, 0, 0, 0); - storage->frame.clear_request = false; - - } else if (!env || env->bg_mode == VS::ENV_BG_CLEAR_COLOR) { - - if (storage->frame.clear_request) { - - clear_color = storage->frame.clear_request_color.to_linear(); - storage->frame.clear_request = false; - } - - } else if (env->bg_mode == VS::ENV_BG_CANVAS) { - - clear_color = env->bg_color.to_linear(); - storage->frame.clear_request = false; - } else if (env->bg_mode == VS::ENV_BG_COLOR) { - - clear_color = env->bg_color.to_linear(); - storage->frame.clear_request = false; - } else if (env->bg_mode == VS::ENV_BG_SKY) { - - storage->frame.clear_request = false; - - } else if (env->bg_mode == VS::ENV_BG_COLOR_SKY) { - - clear_color = env->bg_color.to_linear(); - storage->frame.clear_request = false; - - } else if (env->bg_mode == VS::ENV_BG_CAMERA_FEED) { - feed = CameraServer::get_singleton()->get_feed_by_id(env->camera_feed_id); - storage->frame.clear_request = false; - } else { - storage->frame.clear_request = false; - } - - if (!env || env->bg_mode != VS::ENV_BG_KEEP) { - glClearBufferfv(GL_COLOR, 0, clear_color.components); // specular - } - - VS::EnvironmentBG bg_mode = (!env || (probe && env->bg_mode == VS::ENV_BG_CANVAS)) ? VS::ENV_BG_CLEAR_COLOR : env->bg_mode; //if no environment, or canvas while rendering a probe (invalid use case), use color. - - if (env) { - switch (bg_mode) { - case VS::ENV_BG_COLOR_SKY: - case VS::ENV_BG_SKY: - - sky = storage->sky_owner.getornull(env->sky); - - break; - case VS::ENV_BG_CANVAS: - //copy canvas to 3d buffer and convert it to linear - - glDisable(GL_BLEND); - glDepthMask(GL_FALSE); - glDisable(GL_DEPTH_TEST); - glDisable(GL_CULL_FACE); - - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->color); - - storage->shaders.copy.set_conditional(CopyShaderGLES3::DISABLE_ALPHA, true); - - storage->shaders.copy.set_conditional(CopyShaderGLES3::SRGB_TO_LINEAR, true); - - storage->shaders.copy.bind(); - - _copy_screen(true, true); - - //turn off everything used - storage->shaders.copy.set_conditional(CopyShaderGLES3::SRGB_TO_LINEAR, false); - storage->shaders.copy.set_conditional(CopyShaderGLES3::DISABLE_ALPHA, false); - - //restore - glEnable(GL_BLEND); - glDepthMask(GL_TRUE); - glEnable(GL_DEPTH_TEST); - glEnable(GL_CULL_FACE); - break; - case VS::ENV_BG_CAMERA_FEED: - if (feed.is_valid() && (feed->get_base_width() > 0) && (feed->get_base_height() > 0)) { - // copy our camera feed to our background - - glDisable(GL_BLEND); - glDepthMask(GL_FALSE); - glDisable(GL_DEPTH_TEST); - glDisable(GL_CULL_FACE); - - storage->shaders.copy.set_conditional(CopyShaderGLES3::USE_DISPLAY_TRANSFORM, true); - storage->shaders.copy.set_conditional(CopyShaderGLES3::DISABLE_ALPHA, true); - storage->shaders.copy.set_conditional(CopyShaderGLES3::SRGB_TO_LINEAR, true); - - if (feed->get_datatype() == CameraFeed::FEED_RGB) { - RID camera_RGBA = feed->get_texture(CameraServer::FEED_RGBA_IMAGE); - - VS::get_singleton()->texture_bind(camera_RGBA, 0); - } else if (feed->get_datatype() == CameraFeed::FEED_YCBCR) { - RID camera_YCbCr = feed->get_texture(CameraServer::FEED_YCBCR_IMAGE); - - VS::get_singleton()->texture_bind(camera_YCbCr, 0); - - storage->shaders.copy.set_conditional(CopyShaderGLES3::YCBCR_TO_SRGB, true); - - } else if (feed->get_datatype() == CameraFeed::FEED_YCBCR_SEP) { - RID camera_Y = feed->get_texture(CameraServer::FEED_Y_IMAGE); - RID camera_CbCr = feed->get_texture(CameraServer::FEED_CBCR_IMAGE); - - VS::get_singleton()->texture_bind(camera_Y, 0); - VS::get_singleton()->texture_bind(camera_CbCr, 1); - - storage->shaders.copy.set_conditional(CopyShaderGLES3::SEP_CBCR_TEXTURE, true); - storage->shaders.copy.set_conditional(CopyShaderGLES3::YCBCR_TO_SRGB, true); - }; - - storage->shaders.copy.bind(); - storage->shaders.copy.set_uniform(CopyShaderGLES3::DISPLAY_TRANSFORM, feed->get_transform()); - - _copy_screen(true, true); - - //turn off everything used - storage->shaders.copy.set_conditional(CopyShaderGLES3::USE_DISPLAY_TRANSFORM, false); - storage->shaders.copy.set_conditional(CopyShaderGLES3::DISABLE_ALPHA, false); - storage->shaders.copy.set_conditional(CopyShaderGLES3::SRGB_TO_LINEAR, false); - storage->shaders.copy.set_conditional(CopyShaderGLES3::SEP_CBCR_TEXTURE, false); - storage->shaders.copy.set_conditional(CopyShaderGLES3::YCBCR_TO_SRGB, false); - - //restore - glEnable(GL_BLEND); - glDepthMask(GL_TRUE); - glEnable(GL_DEPTH_TEST); - glEnable(GL_CULL_FACE); - } else { - // don't have a feed, just show greenscreen :) - clear_color = Color(0.0, 1.0, 0.0, 1.0); - } - break; - default: { - } - } - } - - if (probe && probe->probe_ptr->interior) { - sky = NULL; //for rendering probe interiors, radiance must not be used. - } - - state.texscreen_copied = false; - - glBlendEquation(GL_FUNC_ADD); - - if (storage->frame.current_rt && storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]) { - glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - glEnable(GL_BLEND); - } else { - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glDisable(GL_BLEND); - } - - render_list.sort_by_key(false); - - if (state.directional_light_count == 0) { - directional_light = NULL; - _render_list(render_list.elements, render_list.element_count, p_cam_transform, p_cam_projection, sky, false, false, false, false, use_shadows); - } else { - for (int i = 0; i < state.directional_light_count; i++) { - directional_light = directional_lights[i]; - if (i > 0) { - glEnable(GL_BLEND); - } - _setup_directional_light(i, p_cam_transform.affine_inverse(), use_shadows); - _render_list(render_list.elements, render_list.element_count, p_cam_transform, p_cam_projection, sky, false, false, false, i > 0, use_shadows); - } - } - - state.scene_shader.set_conditional(SceneShaderGLES3::USE_MULTIPLE_RENDER_TARGETS, false); - - if (use_mrt) { - GLenum gldb = GL_COLOR_ATTACHMENT0; - glDrawBuffers(1, &gldb); - } - - if (env && env->bg_mode == VS::ENV_BG_SKY && (!storage->frame.current_rt || (!storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT] && state.debug_draw != VS::VIEWPORT_DEBUG_DRAW_OVERDRAW))) { - - /* - if (use_mrt) { - glBindFramebuffer(GL_FRAMEBUFFER,storage->frame.current_rt->buffers.fbo); //switch to alpha fbo for sky, only diffuse/ambient matters - */ - - if (sky && sky->panorama.is_valid()) - _draw_sky(sky, p_cam_projection, p_cam_transform, false, env->sky_custom_fov, env->bg_energy, env->sky_orientation); - } - - //_render_list_forward(&alpha_render_list,camera_transform,camera_transform_inverse,camera_projection,false,fragment_lighting,true); - //glColorMask(1,1,1,1); - - //state.scene_shader.set_conditional( SceneShaderGLES3::USE_FOG,false); - - if (use_mrt) { - - _render_mrts(env, p_cam_projection); - } else { - // Here we have to do the blits/resolves that otherwise are done in the MRT rendering, in particular - // - prepare screen texture for any geometry that uses a shader with screen texture - // - prepare depth texture for any geometry that uses a shader with depth texture - - bool framebuffer_dirty = false; - - if (storage->frame.current_rt && storage->frame.current_rt->buffers.active && state.used_screen_texture) { - glBindFramebuffer(GL_READ_FRAMEBUFFER, storage->frame.current_rt->buffers.fbo); - glReadBuffer(GL_COLOR_ATTACHMENT0); - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, storage->frame.current_rt->effects.mip_maps[0].sizes[0].fbo); - glBlitFramebuffer(0, 0, storage->frame.current_rt->width, storage->frame.current_rt->height, 0, 0, storage->frame.current_rt->width, storage->frame.current_rt->height, GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, GL_NEAREST); - glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); - _blur_effect_buffer(); - framebuffer_dirty = true; - } - - if (storage->frame.current_rt && storage->frame.current_rt->buffers.active && state.used_depth_texture) { - _prepare_depth_texture(); - framebuffer_dirty = true; - } - - if (framebuffer_dirty) { - // Restore framebuffer - glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->buffers.fbo); - glViewport(0, 0, storage->frame.current_rt->width, storage->frame.current_rt->height); - } - } - - if (storage->frame.current_rt && state.used_depth_texture && storage->frame.current_rt->buffers.active) { - _bind_depth_texture(); - } - - if (storage->frame.current_rt && state.used_screen_texture && storage->frame.current_rt->buffers.active) { - glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 7); - glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->effects.mip_maps[0].color); - } - - glEnable(GL_BLEND); - glDepthMask(GL_TRUE); - glEnable(GL_DEPTH_TEST); - glDisable(GL_SCISSOR_TEST); - - render_list.sort_by_reverse_depth_and_priority(true); - - if (state.directional_light_count == 0) { - directional_light = NULL; - _render_list(&render_list.elements[render_list.max_elements - render_list.alpha_element_count], render_list.alpha_element_count, p_cam_transform, p_cam_projection, sky, false, true, false, false, use_shadows); - } else { - for (int i = 0; i < state.directional_light_count; i++) { - directional_light = directional_lights[i]; - _setup_directional_light(i, p_cam_transform.affine_inverse(), use_shadows); - _render_list(&render_list.elements[render_list.max_elements - render_list.alpha_element_count], render_list.alpha_element_count, p_cam_transform, p_cam_projection, sky, false, true, false, i > 0, use_shadows); - } - } - - if (probe) { - //rendering a probe, do no more! - return; - } - - if (env && (env->dof_blur_far_enabled || env->dof_blur_near_enabled) && storage->frame.current_rt && storage->frame.current_rt->buffers.active) - _prepare_depth_texture(); - _post_process(env, p_cam_projection); - // Needed only for debugging - /* if (shadow_atlas && storage->frame.current_rt) { - - //_copy_texture_to_front_buffer(shadow_atlas->depth); - storage->canvas->canvas_begin(); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, shadow_atlas->depth); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE); - storage->canvas->draw_generic_textured_rect(Rect2(0, 0, storage->frame.current_rt->width / 2, storage->frame.current_rt->height / 2), Rect2(0, 0, 1, 1)); - } - - if (storage->frame.current_rt) { - - //_copy_texture_to_front_buffer(shadow_atlas->depth); - storage->canvas->canvas_begin(); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, exposure_shrink[4].color); - //glBindTexture(GL_TEXTURE_2D,storage->frame.current_rt->exposure.color); - storage->canvas->draw_generic_textured_rect(Rect2(0, 0, storage->frame.current_rt->width / 16, storage->frame.current_rt->height / 16), Rect2(0, 0, 1, 1)); - } - - if (reflection_atlas && storage->frame.current_rt) { - - //_copy_texture_to_front_buffer(shadow_atlas->depth); - storage->canvas->canvas_begin(); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, reflection_atlas->color); - storage->canvas->draw_generic_textured_rect(Rect2(0, 0, storage->frame.current_rt->width / 2, storage->frame.current_rt->height / 2), Rect2(0, 0, 1, 1)); - } - - if (directional_shadow.fbo) { - - //_copy_texture_to_front_buffer(shadow_atlas->depth); - storage->canvas->canvas_begin(); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, directional_shadow.depth); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE); - storage->canvas->draw_generic_textured_rect(Rect2(0, 0, storage->frame.current_rt->width / 2, storage->frame.current_rt->height / 2), Rect2(0, 0, 1, 1)); - } - - if ( env_radiance_tex) { - - //_copy_texture_to_front_buffer(shadow_atlas->depth); - storage->canvas->canvas_begin(); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, env_radiance_tex); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - storage->canvas->draw_generic_textured_rect(Rect2(0, 0, storage->frame.current_rt->width / 2, storage->frame.current_rt->height / 2), Rect2(0, 0, 1, 1)); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - }*/ - //disable all stuff -} - -void RasterizerSceneGLES3::render_shadow(RID p_light, RID p_shadow_atlas, int p_pass, InstanceBase **p_cull_result, int p_cull_count) { - - render_pass++; - - directional_light = NULL; - - LightInstance *light_instance = light_instance_owner.getornull(p_light); - ERR_FAIL_COND(!light_instance); - RasterizerStorageGLES3::Light *light = storage->light_owner.getornull(light_instance->light); - ERR_FAIL_COND(!light); - - uint32_t x, y, width, height; - - float dp_direction = 0.0; - float zfar = 0; - bool flip_facing = false; - int custom_vp_size = 0; - GLuint fbo; - int current_cubemap = -1; - float bias = 0; - float normal_bias = 0; - - state.used_depth_prepass = false; - - CameraMatrix light_projection; - Transform light_transform; - - if (light->type == VS::LIGHT_DIRECTIONAL) { - //set pssm stuff - if (light_instance->last_scene_shadow_pass != scene_pass) { - //assign rect if unassigned - light_instance->light_directional_index = directional_shadow.current_light; - light_instance->last_scene_shadow_pass = scene_pass; - directional_shadow.current_light++; - - if (directional_shadow.light_count == 1) { - light_instance->directional_rect = Rect2(0, 0, directional_shadow.size, directional_shadow.size); - } else if (directional_shadow.light_count == 2) { - light_instance->directional_rect = Rect2(0, 0, directional_shadow.size, directional_shadow.size / 2); - if (light_instance->light_directional_index == 1) { - light_instance->directional_rect.position.x += light_instance->directional_rect.size.x; - } - } else { //3 and 4 - light_instance->directional_rect = Rect2(0, 0, directional_shadow.size / 2, directional_shadow.size / 2); - if (light_instance->light_directional_index & 1) { - light_instance->directional_rect.position.x += light_instance->directional_rect.size.x; - } - if (light_instance->light_directional_index / 2) { - light_instance->directional_rect.position.y += light_instance->directional_rect.size.y; - } - } - } - - light_projection = light_instance->shadow_transform[p_pass].camera; - light_transform = light_instance->shadow_transform[p_pass].transform; - - x = light_instance->directional_rect.position.x; - y = light_instance->directional_rect.position.y; - width = light_instance->directional_rect.size.x; - height = light_instance->directional_rect.size.y; - - if (light->directional_shadow_mode == VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS) { - - width /= 2; - height /= 2; - - if (p_pass == 1) { - x += width; - } else if (p_pass == 2) { - y += height; - } else if (p_pass == 3) { - x += width; - y += height; - } - - } else if (light->directional_shadow_mode == VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS) { - - height /= 2; - - if (p_pass == 0) { - - } else { - y += height; - } - } - - float bias_mult = Math::lerp(1.0f, light_instance->shadow_transform[p_pass].bias_scale, light->param[VS::LIGHT_PARAM_SHADOW_BIAS_SPLIT_SCALE]); - zfar = light->param[VS::LIGHT_PARAM_RANGE]; - bias = light->param[VS::LIGHT_PARAM_SHADOW_BIAS] * bias_mult; - normal_bias = light->param[VS::LIGHT_PARAM_SHADOW_NORMAL_BIAS] * bias_mult; - fbo = directional_shadow.fbo; - - } else { - //set from shadow atlas - - ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_shadow_atlas); - ERR_FAIL_COND(!shadow_atlas); - ERR_FAIL_COND(!shadow_atlas->shadow_owners.has(p_light)); - - fbo = shadow_atlas->fbo; - - uint32_t key = shadow_atlas->shadow_owners[p_light]; - - uint32_t quadrant = (key >> ShadowAtlas::QUADRANT_SHIFT) & 0x3; - uint32_t shadow = key & ShadowAtlas::SHADOW_INDEX_MASK; - - ERR_FAIL_INDEX((int)shadow, shadow_atlas->quadrants[quadrant].shadows.size()); - - uint32_t quadrant_size = shadow_atlas->size >> 1; - - x = (quadrant & 1) * quadrant_size; - y = (quadrant >> 1) * quadrant_size; - - uint32_t shadow_size = (quadrant_size / shadow_atlas->quadrants[quadrant].subdivision); - x += (shadow % shadow_atlas->quadrants[quadrant].subdivision) * shadow_size; - y += (shadow / shadow_atlas->quadrants[quadrant].subdivision) * shadow_size; - - width = shadow_size; - height = shadow_size; - - if (light->type == VS::LIGHT_OMNI) { - - if (light->omni_shadow_mode == VS::LIGHT_OMNI_SHADOW_CUBE) { - - int cubemap_index = shadow_cubemaps.size() - 1; - - for (int i = shadow_cubemaps.size() - 1; i >= 0; i--) { - //find appropriate cubemap to render to - if (shadow_cubemaps[i].size > shadow_size * 2) - break; - - cubemap_index = i; - } - - fbo = shadow_cubemaps[cubemap_index].fbo_id[p_pass]; - light_projection = light_instance->shadow_transform[0].camera; - light_transform = light_instance->shadow_transform[0].transform; - custom_vp_size = shadow_cubemaps[cubemap_index].size; - zfar = light->param[VS::LIGHT_PARAM_RANGE]; - - current_cubemap = cubemap_index; - - } else { - - light_projection = light_instance->shadow_transform[0].camera; - light_transform = light_instance->shadow_transform[0].transform; - - if (light->omni_shadow_detail == VS::LIGHT_OMNI_SHADOW_DETAIL_HORIZONTAL) { - - height /= 2; - y += p_pass * height; - } else { - width /= 2; - x += p_pass * width; - } - - dp_direction = p_pass == 0 ? 1.0 : -1.0; - flip_facing = (p_pass == 1); - zfar = light->param[VS::LIGHT_PARAM_RANGE]; - bias = light->param[VS::LIGHT_PARAM_SHADOW_BIAS]; - - state.scene_shader.set_conditional(SceneShaderGLES3::RENDER_DEPTH_DUAL_PARABOLOID, true); - } - - } else if (light->type == VS::LIGHT_SPOT) { - - light_projection = light_instance->shadow_transform[0].camera; - light_transform = light_instance->shadow_transform[0].transform; - - dp_direction = 1.0; - flip_facing = false; - zfar = light->param[VS::LIGHT_PARAM_RANGE]; - bias = light->param[VS::LIGHT_PARAM_SHADOW_BIAS]; - normal_bias = light->param[VS::LIGHT_PARAM_SHADOW_NORMAL_BIAS]; - } - } - - render_list.clear(); - _fill_render_list(p_cull_result, p_cull_count, true, true); - - render_list.sort_by_depth(false); //shadow is front to back for performance - - glDisable(GL_BLEND); - glDisable(GL_DITHER); - glEnable(GL_DEPTH_TEST); - glBindFramebuffer(GL_FRAMEBUFFER, fbo); - glDepthMask(true); - glColorMask(0, 0, 0, 0); - - if (custom_vp_size) { - glViewport(0, 0, custom_vp_size, custom_vp_size); - glScissor(0, 0, custom_vp_size, custom_vp_size); - - } else { - glViewport(x, y, width, height); - glScissor(x, y, width, height); - } - - glEnable(GL_SCISSOR_TEST); - glClearDepth(1.0f); - glClear(GL_DEPTH_BUFFER_BIT); - glDisable(GL_SCISSOR_TEST); - - state.ubo_data.z_offset = bias; - state.ubo_data.z_slope_scale = normal_bias; - state.ubo_data.shadow_dual_paraboloid_render_side = dp_direction; - state.ubo_data.shadow_dual_paraboloid_render_zfar = zfar; - state.ubo_data.opaque_prepass_threshold = 0.1; - - _setup_environment(NULL, light_projection, light_transform); - - state.scene_shader.set_conditional(SceneShaderGLES3::RENDER_DEPTH, true); - - if (light->reverse_cull) { - flip_facing = !flip_facing; - } - _render_list(render_list.elements, render_list.element_count, light_transform, light_projection, NULL, flip_facing, false, true, false, false); - - state.scene_shader.set_conditional(SceneShaderGLES3::RENDER_DEPTH, false); - state.scene_shader.set_conditional(SceneShaderGLES3::RENDER_DEPTH_DUAL_PARABOLOID, false); - - if (light->type == VS::LIGHT_OMNI && light->omni_shadow_mode == VS::LIGHT_OMNI_SHADOW_CUBE && p_pass == 5) { - //convert the chosen cubemap to dual paraboloid! - - ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_shadow_atlas); - - glBindFramebuffer(GL_FRAMEBUFFER, shadow_atlas->fbo); - state.cube_to_dp_shader.bind(); - - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_CUBE_MAP, shadow_cubemaps[current_cubemap].cubemap); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_COMPARE_MODE, GL_NONE); - glDisable(GL_CULL_FACE); - - for (int i = 0; i < 2; i++) { - - state.cube_to_dp_shader.set_uniform(CubeToDpShaderGLES3::Z_FLIP, i == 1); - state.cube_to_dp_shader.set_uniform(CubeToDpShaderGLES3::Z_NEAR, light_projection.get_z_near()); - state.cube_to_dp_shader.set_uniform(CubeToDpShaderGLES3::Z_FAR, light_projection.get_z_far()); - state.cube_to_dp_shader.set_uniform(CubeToDpShaderGLES3::BIAS, light->param[VS::LIGHT_PARAM_SHADOW_BIAS]); - - uint32_t local_width = width, local_height = height; - uint32_t local_x = x, local_y = y; - if (light->omni_shadow_detail == VS::LIGHT_OMNI_SHADOW_DETAIL_HORIZONTAL) { - - local_height /= 2; - local_y += i * local_height; - } else { - local_width /= 2; - local_x += i * local_width; - } - - glViewport(local_x, local_y, local_width, local_height); - glScissor(local_x, local_y, local_width, local_height); - glEnable(GL_SCISSOR_TEST); - glClearDepth(1.0f); - glClear(GL_DEPTH_BUFFER_BIT); - glDisable(GL_SCISSOR_TEST); - //glDisable(GL_DEPTH_TEST); - glDisable(GL_BLEND); - - _copy_screen(); - } - } - - glColorMask(1, 1, 1, 1); -} - -void RasterizerSceneGLES3::set_scene_pass(uint64_t p_pass) { - scene_pass = p_pass; -} - -bool RasterizerSceneGLES3::free(RID p_rid) { - - if (light_instance_owner.owns(p_rid)) { - - LightInstance *light_instance = light_instance_owner.getptr(p_rid); - - //remove from shadow atlases.. - for (Set<RID>::Element *E = light_instance->shadow_atlases.front(); E; E = E->next()) { - ShadowAtlas *shadow_atlas = shadow_atlas_owner.get(E->get()); - ERR_CONTINUE(!shadow_atlas->shadow_owners.has(p_rid)); - uint32_t key = shadow_atlas->shadow_owners[p_rid]; - uint32_t q = (key >> ShadowAtlas::QUADRANT_SHIFT) & 0x3; - uint32_t s = key & ShadowAtlas::SHADOW_INDEX_MASK; - - shadow_atlas->quadrants[q].shadows.write[s].owner = RID(); - shadow_atlas->shadow_owners.erase(p_rid); - } - - light_instance_owner.free(p_rid); - memdelete(light_instance); - - } else if (shadow_atlas_owner.owns(p_rid)) { - - ShadowAtlas *shadow_atlas = shadow_atlas_owner.get(p_rid); - shadow_atlas_set_size(p_rid, 0); - shadow_atlas_owner.free(p_rid); - memdelete(shadow_atlas); - } else if (reflection_atlas_owner.owns(p_rid)) { - - ReflectionAtlas *reflection_atlas = reflection_atlas_owner.get(p_rid); - reflection_atlas_set_size(p_rid, 0); - reflection_atlas_owner.free(p_rid); - memdelete(reflection_atlas); - } else if (reflection_probe_instance_owner.owns(p_rid)) { - - ReflectionProbeInstance *reflection_instance = reflection_probe_instance_owner.get(p_rid); - - reflection_probe_release_atlas_index(p_rid); - reflection_probe_instance_owner.free(p_rid); - memdelete(reflection_instance); - - } else if (environment_owner.owns(p_rid)) { - - Environment *environment = environment_owner.get(p_rid); - - environment_owner.free(p_rid); - memdelete(environment); - - } else if (gi_probe_instance_owner.owns(p_rid)) { - - GIProbeInstance *gi_probe_instance = gi_probe_instance_owner.get(p_rid); - - gi_probe_instance_owner.free(p_rid); - memdelete(gi_probe_instance); - - } else { - return false; - } - - return true; -} - -void RasterizerSceneGLES3::set_debug_draw_mode(VS::ViewportDebugDraw p_debug_draw) { - - state.debug_draw = p_debug_draw; -} - -void RasterizerSceneGLES3::initialize() { - - render_pass = 0; - - state.scene_shader.init(); - - { - //default material and shader - - default_shader = storage->shader_create(); - storage->shader_set_code(default_shader, "shader_type spatial;\n"); - default_material = storage->material_create(); - storage->material_set_shader(default_material, default_shader); - - default_shader_twosided = storage->shader_create(); - default_material_twosided = storage->material_create(); - storage->shader_set_code(default_shader_twosided, "shader_type spatial; render_mode cull_disabled;\n"); - storage->material_set_shader(default_material_twosided, default_shader_twosided); - - //default for shaders using world coordinates (typical for triplanar) - - default_worldcoord_shader = storage->shader_create(); - storage->shader_set_code(default_worldcoord_shader, "shader_type spatial; render_mode world_vertex_coords;\n"); - default_worldcoord_material = storage->material_create(); - storage->material_set_shader(default_worldcoord_material, default_worldcoord_shader); - - default_worldcoord_shader_twosided = storage->shader_create(); - default_worldcoord_material_twosided = storage->material_create(); - storage->shader_set_code(default_worldcoord_shader_twosided, "shader_type spatial; render_mode cull_disabled,world_vertex_coords;\n"); - storage->material_set_shader(default_worldcoord_material_twosided, default_worldcoord_shader_twosided); - } - - { - //default material and shader - - default_overdraw_shader = storage->shader_create(); - storage->shader_set_code(default_overdraw_shader, "shader_type spatial;\nrender_mode blend_add,unshaded;\n void fragment() { ALBEDO=vec3(0.4,0.8,0.8); ALPHA=0.2; }"); - default_overdraw_material = storage->material_create(); - storage->material_set_shader(default_overdraw_material, default_overdraw_shader); - } - - glGenBuffers(1, &state.scene_ubo); - glBindBuffer(GL_UNIFORM_BUFFER, state.scene_ubo); - glBufferData(GL_UNIFORM_BUFFER, sizeof(State::SceneDataUBO), &state.scene_ubo, GL_DYNAMIC_DRAW); - glBindBuffer(GL_UNIFORM_BUFFER, 0); - - glGenBuffers(1, &state.env_radiance_ubo); - glBindBuffer(GL_UNIFORM_BUFFER, state.env_radiance_ubo); - glBufferData(GL_UNIFORM_BUFFER, sizeof(State::EnvironmentRadianceUBO), &state.env_radiance_ubo, GL_DYNAMIC_DRAW); - glBindBuffer(GL_UNIFORM_BUFFER, 0); - - render_list.max_elements = GLOBAL_DEF_RST("rendering/limits/rendering/max_renderable_elements", (int)RenderList::DEFAULT_MAX_ELEMENTS); - ProjectSettings::get_singleton()->set_custom_property_info("rendering/limits/rendering/max_renderable_elements", PropertyInfo(Variant::INT, "rendering/limits/rendering/max_renderable_elements", PROPERTY_HINT_RANGE, "1024,1000000,1")); - render_list.max_lights = GLOBAL_DEF("rendering/limits/rendering/max_renderable_lights", (int)RenderList::DEFAULT_MAX_LIGHTS); - ProjectSettings::get_singleton()->set_custom_property_info("rendering/limits/rendering/max_renderable_lights", PropertyInfo(Variant::INT, "rendering/limits/rendering/max_renderable_lights", PROPERTY_HINT_RANGE, "16,4096,1")); - render_list.max_reflections = GLOBAL_DEF("rendering/limits/rendering/max_renderable_reflections", (int)RenderList::DEFAULT_MAX_REFLECTIONS); - ProjectSettings::get_singleton()->set_custom_property_info("rendering/limits/rendering/max_renderable_reflections", PropertyInfo(Variant::INT, "rendering/limits/rendering/max_renderable_reflections", PROPERTY_HINT_RANGE, "8,1024,1")); - - { - //quad buffers - - glGenBuffers(1, &state.sky_verts); - glBindBuffer(GL_ARRAY_BUFFER, state.sky_verts); - glBufferData(GL_ARRAY_BUFFER, sizeof(Vector3) * 8, NULL, GL_DYNAMIC_DRAW); - glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind - - glGenVertexArrays(1, &state.sky_array); - glBindVertexArray(state.sky_array); - glBindBuffer(GL_ARRAY_BUFFER, state.sky_verts); - glVertexAttribPointer(VS::ARRAY_VERTEX, 3, GL_FLOAT, GL_FALSE, sizeof(Vector3) * 2, 0); - glEnableVertexAttribArray(VS::ARRAY_VERTEX); - glVertexAttribPointer(VS::ARRAY_TEX_UV, 3, GL_FLOAT, GL_FALSE, sizeof(Vector3) * 2, CAST_INT_TO_UCHAR_PTR(sizeof(Vector3))); - glEnableVertexAttribArray(VS::ARRAY_TEX_UV); - glBindVertexArray(0); - glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind - } - render_list.init(); - state.cube_to_dp_shader.init(); - - shadow_atlas_realloc_tolerance_msec = 500; - - int max_shadow_cubemap_sampler_size = 512; - - int cube_size = max_shadow_cubemap_sampler_size; - - glActiveTexture(GL_TEXTURE0); - - while (cube_size >= 32) { - - ShadowCubeMap cube; - cube.size = cube_size; - - glGenTextures(1, &cube.cubemap); - glBindTexture(GL_TEXTURE_CUBE_MAP, cube.cubemap); - //gen cubemap first - for (int i = 0; i < 6; i++) { - - glTexImage2D(_cube_side_enum[i], 0, GL_DEPTH_COMPONENT24, cube.size, cube.size, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL); - } - - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - // Remove artifact on the edges of the shadowmap - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); - - //gen renderbuffers second, because it needs a complete cubemap - for (int i = 0; i < 6; i++) { - - glGenFramebuffers(1, &cube.fbo_id[i]); - glBindFramebuffer(GL_FRAMEBUFFER, cube.fbo_id[i]); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, _cube_side_enum[i], cube.cubemap, 0); - - GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); - ERR_CONTINUE(status != GL_FRAMEBUFFER_COMPLETE); - } - - shadow_cubemaps.push_back(cube); - - cube_size >>= 1; - } - - { - //directional light shadow - directional_shadow.light_count = 0; - directional_shadow.size = next_power_of_2(GLOBAL_GET("rendering/quality/directional_shadow/size")); - glGenFramebuffers(1, &directional_shadow.fbo); - glBindFramebuffer(GL_FRAMEBUFFER, directional_shadow.fbo); - glGenTextures(1, &directional_shadow.depth); - glBindTexture(GL_TEXTURE_2D, directional_shadow.depth); - glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, directional_shadow.size, directional_shadow.size, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - 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_R, GL_CLAMP_TO_EDGE); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, directional_shadow.depth, 0); - GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); - if (status != GL_FRAMEBUFFER_COMPLETE) { - ERR_PRINT("Directional shadow framebuffer status invalid"); - } - } - - { - //spot and omni ubos - - int max_ubo_size; - glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &max_ubo_size); - const int ubo_light_size = 160; - state.ubo_light_size = ubo_light_size; - state.max_ubo_lights = MIN(render_list.max_lights, max_ubo_size / ubo_light_size); - - state.spot_array_tmp = (uint8_t *)memalloc(ubo_light_size * state.max_ubo_lights); - state.omni_array_tmp = (uint8_t *)memalloc(ubo_light_size * state.max_ubo_lights); - - glGenBuffers(1, &state.spot_array_ubo); - glBindBuffer(GL_UNIFORM_BUFFER, state.spot_array_ubo); - glBufferData(GL_UNIFORM_BUFFER, ubo_light_size * state.max_ubo_lights, NULL, GL_DYNAMIC_DRAW); - glBindBuffer(GL_UNIFORM_BUFFER, 0); - - glGenBuffers(1, &state.omni_array_ubo); - glBindBuffer(GL_UNIFORM_BUFFER, state.omni_array_ubo); - glBufferData(GL_UNIFORM_BUFFER, ubo_light_size * state.max_ubo_lights, NULL, GL_DYNAMIC_DRAW); - glBindBuffer(GL_UNIFORM_BUFFER, 0); - - glGenBuffers(1, &state.directional_ubo); - glBindBuffer(GL_UNIFORM_BUFFER, state.directional_ubo); - glBufferData(GL_UNIFORM_BUFFER, sizeof(LightDataUBO), NULL, GL_DYNAMIC_DRAW); - glBindBuffer(GL_UNIFORM_BUFFER, 0); - - state.max_forward_lights_per_object = 8; - - state.scene_shader.add_custom_define("#define MAX_LIGHT_DATA_STRUCTS " + itos(state.max_ubo_lights) + "\n"); - state.scene_shader.add_custom_define("#define MAX_FORWARD_LIGHTS " + itos(state.max_forward_lights_per_object) + "\n"); - - state.max_ubo_reflections = MIN(render_list.max_reflections, max_ubo_size / (int)sizeof(ReflectionProbeDataUBO)); - - state.reflection_array_tmp = (uint8_t *)memalloc(sizeof(ReflectionProbeDataUBO) * state.max_ubo_reflections); - - glGenBuffers(1, &state.reflection_array_ubo); - glBindBuffer(GL_UNIFORM_BUFFER, state.reflection_array_ubo); - glBufferData(GL_UNIFORM_BUFFER, sizeof(ReflectionProbeDataUBO) * state.max_ubo_reflections, NULL, GL_DYNAMIC_DRAW); - glBindBuffer(GL_UNIFORM_BUFFER, 0); - - state.scene_shader.add_custom_define("#define MAX_REFLECTION_DATA_STRUCTS " + itos(state.max_ubo_reflections) + "\n"); - - state.max_skeleton_bones = MIN(2048, max_ubo_size / (12 * sizeof(float))); - state.scene_shader.add_custom_define("#define MAX_SKELETON_BONES " + itos(state.max_skeleton_bones) + "\n"); - } - - shadow_filter_mode = SHADOW_FILTER_NEAREST; - - { //reflection cubemaps - int max_reflection_cubemap_sampler_size = 512; - - int rcube_size = max_reflection_cubemap_sampler_size; - - glActiveTexture(GL_TEXTURE0); - - bool use_float = true; - - GLenum internal_format = use_float ? GL_RGBA16F : GL_RGB10_A2; - GLenum format = GL_RGBA; - GLenum type = use_float ? GL_HALF_FLOAT : GL_UNSIGNED_INT_2_10_10_10_REV; - - while (rcube_size >= 32) { - - ReflectionCubeMap cube; - cube.size = rcube_size; - - glGenTextures(1, &cube.depth); - glBindTexture(GL_TEXTURE_2D, cube.depth); - glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, cube.size, cube.size, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL); - 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_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - glGenTextures(1, &cube.cubemap); - glBindTexture(GL_TEXTURE_CUBE_MAP, cube.cubemap); - //gen cubemap first - for (int i = 0; i < 6; i++) { - - glTexImage2D(_cube_side_enum[i], 0, internal_format, cube.size, cube.size, 0, format, type, NULL); - } - - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - // Remove artifact on the edges of the reflectionmap - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); - - //gen renderbuffers second, because it needs a complete cubemap - for (int i = 0; i < 6; i++) { - - glGenFramebuffers(1, &cube.fbo_id[i]); - glBindFramebuffer(GL_FRAMEBUFFER, cube.fbo_id[i]); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, _cube_side_enum[i], cube.cubemap, 0); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, cube.depth, 0); - - GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); - ERR_CONTINUE(status != GL_FRAMEBUFFER_COMPLETE); - } - - reflection_cubemaps.push_back(cube); - - rcube_size >>= 1; - } - } - - { - - uint32_t immediate_buffer_size = GLOBAL_DEF("rendering/limits/buffers/immediate_buffer_size_kb", 2048); - ProjectSettings::get_singleton()->set_custom_property_info("rendering/limits/buffers/immediate_buffer_size_kb", PropertyInfo(Variant::INT, "rendering/limits/buffers/immediate_buffer_size_kb", PROPERTY_HINT_RANGE, "0,8192,1,or_greater")); - - glGenBuffers(1, &state.immediate_buffer); - glBindBuffer(GL_ARRAY_BUFFER, state.immediate_buffer); - glBufferData(GL_ARRAY_BUFFER, immediate_buffer_size * 1024, NULL, GL_DYNAMIC_DRAW); - glBindBuffer(GL_ARRAY_BUFFER, 0); - - glGenVertexArrays(1, &state.immediate_array); - } - -#ifdef GLES_OVER_GL - //"desktop" opengl needs this. - glEnable(GL_PROGRAM_POINT_SIZE); - -#endif - - state.resolve_shader.init(); - state.ssr_shader.init(); - state.effect_blur_shader.init(); - state.sss_shader.init(); - state.ssao_minify_shader.init(); - state.ssao_shader.init(); - state.ssao_blur_shader.init(); - state.exposure_shader.init(); - state.tonemap_shader.init(); - - { - GLOBAL_DEF("rendering/quality/subsurface_scattering/quality", 1); - ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/subsurface_scattering/quality", PropertyInfo(Variant::INT, "rendering/quality/subsurface_scattering/quality", PROPERTY_HINT_ENUM, "Low,Medium,High")); - GLOBAL_DEF("rendering/quality/subsurface_scattering/scale", 1.0); - ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/subsurface_scattering/scale", PropertyInfo(Variant::INT, "rendering/quality/subsurface_scattering/scale", PROPERTY_HINT_RANGE, "0.01,8,0.01")); - GLOBAL_DEF("rendering/quality/subsurface_scattering/follow_surface", false); - GLOBAL_DEF("rendering/quality/subsurface_scattering/weight_samples", true); - - GLOBAL_DEF("rendering/quality/voxel_cone_tracing/high_quality", false); - } - - exposure_shrink_size = 243; - int max_exposure_shrink_size = exposure_shrink_size; - - while (max_exposure_shrink_size > 0) { - - RasterizerStorageGLES3::RenderTarget::Exposure e; - - glGenFramebuffers(1, &e.fbo); - glBindFramebuffer(GL_FRAMEBUFFER, e.fbo); - - glGenTextures(1, &e.color); - glBindTexture(GL_TEXTURE_2D, e.color); - - if (storage->config.framebuffer_float_supported) { - glTexImage2D(GL_TEXTURE_2D, 0, GL_R32F, max_exposure_shrink_size, max_exposure_shrink_size, 0, GL_RED, GL_FLOAT, NULL); - } else if (storage->config.framebuffer_half_float_supported) { - glTexImage2D(GL_TEXTURE_2D, 0, GL_R16F, max_exposure_shrink_size, max_exposure_shrink_size, 0, GL_RED, GL_HALF_FLOAT, NULL); - } else { - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB10_A2, max_exposure_shrink_size, max_exposure_shrink_size, 0, GL_RED, GL_UNSIGNED_INT_2_10_10_10_REV, NULL); - } - - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, e.color, 0); - 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_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - exposure_shrink.push_back(e); - max_exposure_shrink_size /= 3; - - GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); - ERR_CONTINUE(status != GL_FRAMEBUFFER_COMPLETE); - } - - state.debug_draw = VS::VIEWPORT_DEBUG_DRAW_DISABLED; - - glFrontFace(GL_CW); -} - -void RasterizerSceneGLES3::iteration() { - - shadow_filter_mode = ShadowFilterMode(int(GLOBAL_GET("rendering/quality/shadows/filter_mode"))); - subsurface_scatter_follow_surface = GLOBAL_GET("rendering/quality/subsurface_scattering/follow_surface"); - subsurface_scatter_weight_samples = GLOBAL_GET("rendering/quality/subsurface_scattering/weight_samples"); - subsurface_scatter_quality = SubSurfaceScatterQuality(int(GLOBAL_GET("rendering/quality/subsurface_scattering/quality"))); - subsurface_scatter_size = GLOBAL_GET("rendering/quality/subsurface_scattering/scale"); - - state.scene_shader.set_conditional(SceneShaderGLES3::VCT_QUALITY_HIGH, GLOBAL_GET("rendering/quality/voxel_cone_tracing/high_quality")); -} - -void RasterizerSceneGLES3::finalize() { -} - -RasterizerSceneGLES3::RasterizerSceneGLES3() { -} - -RasterizerSceneGLES3::~RasterizerSceneGLES3() { - - memdelete(default_material.get_data()); - memdelete(default_material_twosided.get_data()); - memdelete(default_shader.get_data()); - memdelete(default_shader_twosided.get_data()); - - memdelete(default_worldcoord_material.get_data()); - memdelete(default_worldcoord_material_twosided.get_data()); - memdelete(default_worldcoord_shader.get_data()); - memdelete(default_worldcoord_shader_twosided.get_data()); - - memdelete(default_overdraw_material.get_data()); - memdelete(default_overdraw_shader.get_data()); - - memfree(state.spot_array_tmp); - memfree(state.omni_array_tmp); - memfree(state.reflection_array_tmp); -} diff --git a/drivers/gles3/rasterizer_scene_gles3.h b/drivers/gles3/rasterizer_scene_gles3.h deleted file mode 100644 index 7885d7c1b7..0000000000 --- a/drivers/gles3/rasterizer_scene_gles3.h +++ /dev/null @@ -1,879 +0,0 @@ -/*************************************************************************/ -/* rasterizer_scene_gles3.h */ -/*************************************************************************/ -/* 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. */ -/*************************************************************************/ - -#ifndef RASTERIZERSCENEGLES3_H -#define RASTERIZERSCENEGLES3_H - -/* Must come before shaders or the Windows build fails... */ -#include "rasterizer_storage_gles3.h" - -#include "drivers/gles3/shaders/cube_to_dp.glsl.gen.h" -#include "drivers/gles3/shaders/effect_blur.glsl.gen.h" -#include "drivers/gles3/shaders/exposure.glsl.gen.h" -#include "drivers/gles3/shaders/resolve.glsl.gen.h" -#include "drivers/gles3/shaders/scene.glsl.gen.h" -#include "drivers/gles3/shaders/screen_space_reflection.glsl.gen.h" -#include "drivers/gles3/shaders/ssao.glsl.gen.h" -#include "drivers/gles3/shaders/ssao_blur.glsl.gen.h" -#include "drivers/gles3/shaders/ssao_minify.glsl.gen.h" -#include "drivers/gles3/shaders/subsurf_scattering.glsl.gen.h" -#include "drivers/gles3/shaders/tonemap.glsl.gen.h" - -class RasterizerSceneGLES3 : public RasterizerScene { -public: - enum ShadowFilterMode { - SHADOW_FILTER_NEAREST, - SHADOW_FILTER_PCF5, - SHADOW_FILTER_PCF13, - }; - - ShadowFilterMode shadow_filter_mode; - - uint64_t shadow_atlas_realloc_tolerance_msec; - - enum SubSurfaceScatterQuality { - SSS_QUALITY_LOW, - SSS_QUALITY_MEDIUM, - SSS_QUALITY_HIGH, - }; - - SubSurfaceScatterQuality subsurface_scatter_quality; - float subsurface_scatter_size; - bool subsurface_scatter_follow_surface; - bool subsurface_scatter_weight_samples; - - uint64_t render_pass; - uint64_t scene_pass; - uint32_t current_material_index; - uint32_t current_geometry_index; - - RID default_material; - RID default_material_twosided; - RID default_shader; - RID default_shader_twosided; - - RID default_worldcoord_material; - RID default_worldcoord_material_twosided; - RID default_worldcoord_shader; - RID default_worldcoord_shader_twosided; - - RID default_overdraw_material; - RID default_overdraw_shader; - - RasterizerStorageGLES3 *storage; - - Vector<RasterizerStorageGLES3::RenderTarget::Exposure> exposure_shrink; - int exposure_shrink_size; - - struct State { - - bool texscreen_copied; - int current_blend_mode; - float current_line_width; - int current_depth_draw; - bool current_depth_test; - GLuint current_main_tex; - - SceneShaderGLES3 scene_shader; - CubeToDpShaderGLES3 cube_to_dp_shader; - ResolveShaderGLES3 resolve_shader; - ScreenSpaceReflectionShaderGLES3 ssr_shader; - EffectBlurShaderGLES3 effect_blur_shader; - SubsurfScatteringShaderGLES3 sss_shader; - SsaoMinifyShaderGLES3 ssao_minify_shader; - SsaoShaderGLES3 ssao_shader; - SsaoBlurShaderGLES3 ssao_blur_shader; - ExposureShaderGLES3 exposure_shader; - TonemapShaderGLES3 tonemap_shader; - - struct SceneDataUBO { - //this is a std140 compatible struct. Please read the OpenGL 3.3 Specification spec before doing any changes - float projection_matrix[16]; - float inv_projection_matrix[16]; - float camera_inverse_matrix[16]; - float camera_matrix[16]; - float ambient_light_color[4]; - float bg_color[4]; - float fog_color_enabled[4]; - float fog_sun_color_amount[4]; - - float ambient_energy; - float bg_energy; - float z_offset; - float z_slope_scale; - float shadow_dual_paraboloid_render_zfar; - float shadow_dual_paraboloid_render_side; - float viewport_size[2]; - float screen_pixel_size[2]; - float shadow_atlas_pixel_size[2]; - float shadow_directional_pixel_size[2]; - - float time; - float z_far; - float reflection_multiplier; - float subsurface_scatter_width; - float ambient_occlusion_affect_light; - float ambient_occlusion_affect_ssao; - float opaque_prepass_threshold; - - uint32_t fog_depth_enabled; - float fog_depth_begin; - float fog_depth_end; - float fog_density; - float fog_depth_curve; - uint32_t fog_transmit_enabled; - float fog_transmit_curve; - uint32_t fog_height_enabled; - float fog_height_min; - float fog_height_max; - float fog_height_curve; - // make sure this struct is padded to be a multiple of 16 bytes for webgl - float pad[2]; - - } ubo_data; - - GLuint scene_ubo; - - struct EnvironmentRadianceUBO { - - float transform[16]; - float ambient_contribution; - uint8_t padding[12]; - - } env_radiance_data; - - GLuint env_radiance_ubo; - - GLuint sky_verts; - GLuint sky_array; - - GLuint directional_ubo; - - GLuint spot_array_ubo; - GLuint omni_array_ubo; - GLuint reflection_array_ubo; - - GLuint immediate_buffer; - GLuint immediate_array; - - uint32_t ubo_light_size; - uint8_t *spot_array_tmp; - uint8_t *omni_array_tmp; - uint8_t *reflection_array_tmp; - - int max_ubo_lights; - int max_forward_lights_per_object; - int max_ubo_reflections; - int max_skeleton_bones; - - bool used_contact_shadows; - - int spot_light_count; - int omni_light_count; - int directional_light_count; - int reflection_probe_count; - - bool cull_front; - bool cull_disabled; - bool used_sss; - bool used_screen_texture; - - bool used_depth_prepass; - - bool used_depth_texture; - bool prepared_depth_texture; - bool bound_depth_texture; - - VS::ViewportDebugDraw debug_draw; - } state; - - /* SHADOW ATLAS API */ - - struct ShadowAtlas : public RID_Data { - - enum { - QUADRANT_SHIFT = 27, - SHADOW_INDEX_MASK = (1 << QUADRANT_SHIFT) - 1, - SHADOW_INVALID = 0xFFFFFFFF - }; - - struct Quadrant { - - uint32_t subdivision; - - struct Shadow { - RID owner; - uint64_t version; - uint64_t alloc_tick; - - Shadow() { - version = 0; - alloc_tick = 0; - } - }; - - Vector<Shadow> shadows; - - Quadrant() { - subdivision = 0; //not in use - } - - } quadrants[4]; - - int size_order[4]; - uint32_t smallest_subdiv; - - int size; - - GLuint fbo; - GLuint depth; - - Map<RID, uint32_t> shadow_owners; - }; - - struct ShadowCubeMap { - - GLuint fbo_id[6]; - GLuint cubemap; - uint32_t size; - }; - - Vector<ShadowCubeMap> shadow_cubemaps; - - RID_Owner<ShadowAtlas> shadow_atlas_owner; - - RID shadow_atlas_create(); - void shadow_atlas_set_size(RID p_atlas, int p_size); - void shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision); - bool _shadow_atlas_find_shadow(ShadowAtlas *shadow_atlas, int *p_in_quadrants, int p_quadrant_count, int p_current_subdiv, uint64_t p_tick, int &r_quadrant, int &r_shadow); - bool shadow_atlas_update_light(RID p_atlas, RID p_light_intance, float p_coverage, uint64_t p_light_version); - - struct DirectionalShadow { - GLuint fbo; - GLuint depth; - int light_count; - int size; - int current_light; - } directional_shadow; - - virtual int get_directional_light_shadow_size(RID p_light_intance); - virtual void set_directional_shadow_count(int p_count); - - /* REFLECTION PROBE ATLAS API */ - - struct ReflectionAtlas : public RID_Data { - - int subdiv; - int size; - - struct Reflection { - RID owner; - uint64_t last_frame; - }; - - GLuint fbo[6]; - GLuint color; - - Vector<Reflection> reflections; - }; - - mutable RID_Owner<ReflectionAtlas> reflection_atlas_owner; - - virtual RID reflection_atlas_create(); - virtual void reflection_atlas_set_size(RID p_ref_atlas, int p_size); - virtual void reflection_atlas_set_subdivision(RID p_ref_atlas, int p_subdiv); - - /* REFLECTION CUBEMAPS */ - - struct ReflectionCubeMap { - - GLuint fbo_id[6]; - GLuint cubemap; - GLuint depth; - int size; - }; - - Vector<ReflectionCubeMap> reflection_cubemaps; - - /* REFLECTION PROBE INSTANCE */ - - struct ReflectionProbeInstance : public RID_Data { - - RasterizerStorageGLES3::ReflectionProbe *probe_ptr; - RID probe; - RID self; - RID atlas; - - int reflection_atlas_index; - - int render_step; - - uint64_t last_pass; - int reflection_index; - - Transform transform; - }; - - struct ReflectionProbeDataUBO { - - float box_extents[4]; - float box_ofs[4]; - float params[4]; // intensity, 0, 0, boxproject - float ambient[4]; //color, probe contrib - float atlas_clamp[4]; - float local_matrix[16]; //up to here for spot and omni, rest is for directional - //notes: for ambientblend, use distance to edge to blend between already existing global environment - }; - - mutable RID_Owner<ReflectionProbeInstance> reflection_probe_instance_owner; - - virtual RID reflection_probe_instance_create(RID p_probe); - virtual void reflection_probe_instance_set_transform(RID p_instance, const Transform &p_transform); - virtual void reflection_probe_release_atlas_index(RID p_instance); - virtual bool reflection_probe_instance_needs_redraw(RID p_instance); - virtual bool reflection_probe_instance_has_reflection(RID p_instance); - virtual bool reflection_probe_instance_begin_render(RID p_instance, RID p_reflection_atlas); - virtual bool reflection_probe_instance_postprocess_step(RID p_instance); - - /* ENVIRONMENT API */ - - struct Environment : public RID_Data { - - VS::EnvironmentBG bg_mode; - - RID sky; - float sky_custom_fov; - Basis sky_orientation; - - Color bg_color; - float bg_energy; - float sky_ambient; - - int camera_feed_id; - - Color ambient_color; - float ambient_energy; - float ambient_sky_contribution; - - int canvas_max_layer; - - bool ssr_enabled; - int ssr_max_steps; - float ssr_fade_in; - float ssr_fade_out; - float ssr_depth_tolerance; - bool ssr_roughness; - - bool ssao_enabled; - float ssao_intensity; - float ssao_radius; - float ssao_intensity2; - float ssao_radius2; - float ssao_bias; - float ssao_light_affect; - float ssao_ao_channel_affect; - Color ssao_color; - VS::EnvironmentSSAOQuality ssao_quality; - float ssao_bilateral_sharpness; - VS::EnvironmentSSAOBlur ssao_filter; - - bool glow_enabled; - int glow_levels; - float glow_intensity; - float glow_strength; - float glow_bloom; - VS::EnvironmentGlowBlendMode glow_blend_mode; - float glow_hdr_bleed_threshold; - float glow_hdr_bleed_scale; - float glow_hdr_luminance_cap; - bool glow_bicubic_upscale; - - VS::EnvironmentToneMapper tone_mapper; - float tone_mapper_exposure; - float tone_mapper_exposure_white; - bool auto_exposure; - float auto_exposure_speed; - float auto_exposure_min; - float auto_exposure_max; - float auto_exposure_grey; - - bool dof_blur_far_enabled; - float dof_blur_far_distance; - float dof_blur_far_transition; - float dof_blur_far_amount; - VS::EnvironmentDOFBlurQuality dof_blur_far_quality; - - bool dof_blur_near_enabled; - float dof_blur_near_distance; - float dof_blur_near_transition; - float dof_blur_near_amount; - VS::EnvironmentDOFBlurQuality dof_blur_near_quality; - - bool adjustments_enabled; - float adjustments_brightness; - float adjustments_contrast; - float adjustments_saturation; - RID color_correction; - - bool fog_enabled; - Color fog_color; - Color fog_sun_color; - float fog_sun_amount; - - bool fog_depth_enabled; - float fog_depth_begin; - float fog_depth_end; - float fog_depth_curve; - bool fog_transmit_enabled; - float fog_transmit_curve; - bool fog_height_enabled; - float fog_height_min; - float fog_height_max; - float fog_height_curve; - - Environment() : - bg_mode(VS::ENV_BG_CLEAR_COLOR), - sky_custom_fov(0.0), - bg_energy(1.0), - sky_ambient(0), - camera_feed_id(0), - ambient_energy(1.0), - ambient_sky_contribution(0.0), - canvas_max_layer(0), - ssr_enabled(false), - ssr_max_steps(64), - ssr_fade_in(0.15), - ssr_fade_out(2.0), - ssr_depth_tolerance(0.2), - ssr_roughness(true), - ssao_enabled(false), - ssao_intensity(1.0), - ssao_radius(1.0), - ssao_intensity2(1.0), - ssao_radius2(0.0), - ssao_bias(0.01), - ssao_light_affect(0), - ssao_ao_channel_affect(0), - ssao_quality(VS::ENV_SSAO_QUALITY_LOW), - ssao_bilateral_sharpness(4), - ssao_filter(VS::ENV_SSAO_BLUR_3x3), - glow_enabled(false), - glow_levels((1 << 2) | (1 << 4)), - glow_intensity(0.8), - glow_strength(1.0), - glow_bloom(0.0), - glow_blend_mode(VS::GLOW_BLEND_MODE_SOFTLIGHT), - glow_hdr_bleed_threshold(1.0), - glow_hdr_bleed_scale(2.0), - glow_hdr_luminance_cap(12.0), - glow_bicubic_upscale(false), - tone_mapper(VS::ENV_TONE_MAPPER_LINEAR), - tone_mapper_exposure(1.0), - tone_mapper_exposure_white(1.0), - auto_exposure(false), - auto_exposure_speed(0.5), - auto_exposure_min(0.05), - auto_exposure_max(8), - auto_exposure_grey(0.4), - dof_blur_far_enabled(false), - dof_blur_far_distance(10), - dof_blur_far_transition(5), - dof_blur_far_amount(0.1), - dof_blur_far_quality(VS::ENV_DOF_BLUR_QUALITY_MEDIUM), - dof_blur_near_enabled(false), - dof_blur_near_distance(2), - dof_blur_near_transition(1), - dof_blur_near_amount(0.1), - dof_blur_near_quality(VS::ENV_DOF_BLUR_QUALITY_MEDIUM), - adjustments_enabled(false), - adjustments_brightness(1.0), - adjustments_contrast(1.0), - adjustments_saturation(1.0), - fog_enabled(false), - fog_color(Color(0.5, 0.5, 0.5)), - fog_sun_color(Color(0.8, 0.8, 0.0)), - fog_sun_amount(0), - fog_depth_enabled(true), - fog_depth_begin(10), - fog_depth_end(0), - fog_depth_curve(1), - fog_transmit_enabled(true), - fog_transmit_curve(1), - fog_height_enabled(false), - fog_height_min(10), - fog_height_max(0), - fog_height_curve(1) { - } - }; - - RID_Owner<Environment> environment_owner; - - virtual RID environment_create(); - - virtual void environment_set_background(RID p_env, VS::EnvironmentBG p_bg); - virtual void environment_set_sky(RID p_env, RID p_sky); - virtual void environment_set_sky_custom_fov(RID p_env, float p_scale); - virtual void environment_set_sky_orientation(RID p_env, const Basis &p_orientation); - virtual void environment_set_bg_color(RID p_env, const Color &p_color); - virtual void environment_set_bg_energy(RID p_env, float p_energy); - virtual void environment_set_canvas_max_layer(RID p_env, int p_max_layer); - virtual void environment_set_ambient_light(RID p_env, const Color &p_color, float p_energy = 1.0, float p_sky_contribution = 0.0); - virtual void environment_set_camera_feed_id(RID p_env, int p_camera_feed_id); - - virtual void environment_set_dof_blur_near(RID p_env, bool p_enable, float p_distance, float p_transition, float p_amount, VS::EnvironmentDOFBlurQuality p_quality); - virtual void environment_set_dof_blur_far(RID p_env, bool p_enable, float p_distance, float p_transition, float p_amount, VS::EnvironmentDOFBlurQuality p_quality); - virtual void environment_set_glow(RID p_env, bool p_enable, int p_level_flags, float p_intensity, float p_strength, float p_bloom_threshold, VS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap, bool p_bicubic_upscale); - virtual void environment_set_fog(RID p_env, bool p_enable, float p_begin, float p_end, RID p_gradient_texture); - - virtual void environment_set_ssr(RID p_env, bool p_enable, int p_max_steps, float p_fade_in, float p_fade_out, float p_depth_tolerance, bool p_roughness); - virtual void environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_radius2, float p_intensity2, float p_bias, float p_light_affect, float p_ao_channel_affect, const Color &p_color, VS::EnvironmentSSAOQuality p_quality, VS::EnvironmentSSAOBlur p_blur, float p_bilateral_sharpness); - - virtual void environment_set_tonemap(RID p_env, VS::EnvironmentToneMapper p_tone_mapper, float p_exposure, float p_white, bool p_auto_exposure, float p_min_luminance, float p_max_luminance, float p_auto_exp_speed, float p_auto_exp_scale); - - virtual void environment_set_adjustment(RID p_env, bool p_enable, float p_brightness, float p_contrast, float p_saturation, RID p_ramp); - - virtual void environment_set_fog(RID p_env, bool p_enable, const Color &p_color, const Color &p_sun_color, float p_sun_amount); - virtual void environment_set_fog_depth(RID p_env, bool p_enable, float p_depth_begin, float p_depth_end, float p_depth_curve, bool p_transmit, float p_transmit_curve); - virtual void environment_set_fog_height(RID p_env, bool p_enable, float p_min_height, float p_max_height, float p_height_curve); - - virtual bool is_environment(RID p_env); - - virtual VS::EnvironmentBG environment_get_background(RID p_env); - virtual int environment_get_canvas_max_layer(RID p_env); - - /* LIGHT INSTANCE */ - - struct LightDataUBO { - - float light_pos_inv_radius[4]; - float light_direction_attenuation[4]; - float light_color_energy[4]; - float light_params[4]; //spot attenuation, spot angle, specular, shadow enabled - float light_clamp[4]; - float light_shadow_color_contact[4]; - union { - struct { - float matrix1[16]; //up to here for spot and omni, rest is for directional - float matrix2[16]; - float matrix3[16]; - float matrix4[16]; - }; - float matrix[4 * 16]; - } shadow; - float shadow_split_offsets[4]; - }; - - struct LightInstance : public RID_Data { - - struct ShadowTransform { - - CameraMatrix camera; - Transform transform; - float farplane; - float split; - float bias_scale; - }; - - ShadowTransform shadow_transform[4]; - - RID self; - RID light; - RasterizerStorageGLES3::Light *light_ptr; - Transform transform; - - Vector3 light_vector; - Vector3 spot_vector; - float linear_att; - - uint64_t shadow_pass; - uint64_t last_scene_pass; - uint64_t last_scene_shadow_pass; - uint64_t last_pass; - uint16_t light_index; - uint16_t light_directional_index; - - uint32_t current_shadow_atlas_key; - - Vector2 dp; - - Rect2 directional_rect; - - Set<RID> shadow_atlases; //shadow atlases where this light is registered - - LightInstance() {} - }; - - mutable RID_Owner<LightInstance> light_instance_owner; - - virtual RID light_instance_create(RID p_light); - virtual void light_instance_set_transform(RID p_light_instance, const Transform &p_transform); - virtual void light_instance_set_shadow_transform(RID p_light_instance, const CameraMatrix &p_projection, const Transform &p_transform, float p_far, float p_split, int p_pass, float p_bias_scale = 1.0); - virtual void light_instance_mark_visible(RID p_light_instance); - - /* REFLECTION INSTANCE */ - - struct GIProbeInstance : public RID_Data { - RID data; - RasterizerStorageGLES3::GIProbe *probe; - GLuint tex_cache; - Vector3 cell_size_cache; - Vector3 bounds; - Transform transform_to_data; - - GIProbeInstance() : - probe(NULL), - tex_cache(0) { - } - }; - - mutable RID_Owner<GIProbeInstance> gi_probe_instance_owner; - - virtual RID gi_probe_instance_create(); - virtual void gi_probe_instance_set_light_data(RID p_probe, RID p_base, RID p_data); - virtual void gi_probe_instance_set_transform_to_data(RID p_probe, const Transform &p_xform); - virtual void gi_probe_instance_set_bounds(RID p_probe, const Vector3 &p_bounds); - - /* RENDER LIST */ - - struct RenderList { - - enum { - DEFAULT_MAX_ELEMENTS = 65536, - SORT_FLAG_SKELETON = 1, - SORT_FLAG_INSTANCING = 2, - MAX_DIRECTIONAL_LIGHTS = 16, - DEFAULT_MAX_LIGHTS = 4096, - DEFAULT_MAX_REFLECTIONS = 1024, - - SORT_KEY_PRIORITY_SHIFT = 56, - SORT_KEY_PRIORITY_MASK = 0xFF, - //depth layer for opaque (56-52) - SORT_KEY_OPAQUE_DEPTH_LAYER_SHIFT = 52, - SORT_KEY_OPAQUE_DEPTH_LAYER_MASK = 0xF, -//64 bits unsupported in MSVC -#define SORT_KEY_UNSHADED_FLAG (uint64_t(1) << 49) -#define SORT_KEY_NO_DIRECTIONAL_FLAG (uint64_t(1) << 48) -#define SORT_KEY_LIGHTMAP_CAPTURE_FLAG (uint64_t(1) << 47) -#define SORT_KEY_LIGHTMAP_FLAG (uint64_t(1) << 46) -#define SORT_KEY_GI_PROBES_FLAG (uint64_t(1) << 45) -#define SORT_KEY_VERTEX_LIT_FLAG (uint64_t(1) << 44) - SORT_KEY_SHADING_SHIFT = 44, - SORT_KEY_SHADING_MASK = 63, - //44-28 material index - SORT_KEY_MATERIAL_INDEX_SHIFT = 28, - //28-8 geometry index - SORT_KEY_GEOMETRY_INDEX_SHIFT = 8, - //bits 5-7 geometry type - SORT_KEY_GEOMETRY_TYPE_SHIFT = 5, - //bits 0-5 for flags - SORT_KEY_OPAQUE_PRE_PASS = 8, - SORT_KEY_CULL_DISABLED_FLAG = 4, - SORT_KEY_SKELETON_FLAG = 2, - SORT_KEY_MIRROR_FLAG = 1 - - }; - - int max_elements; - int max_lights; - int max_reflections; - - struct Element { - - RasterizerScene::InstanceBase *instance; - RasterizerStorageGLES3::Geometry *geometry; - RasterizerStorageGLES3::Material *material; - RasterizerStorageGLES3::GeometryOwner *owner; - uint64_t sort_key; - }; - - Element *base_elements; - Element **elements; - - int element_count; - int alpha_element_count; - - void clear() { - - element_count = 0; - alpha_element_count = 0; - } - - //should eventually be replaced by radix - - struct SortByKey { - - _FORCE_INLINE_ bool operator()(const Element *A, const Element *B) const { - return A->sort_key < B->sort_key; - } - }; - - void sort_by_key(bool p_alpha) { - - SortArray<Element *, SortByKey> sorter; - if (p_alpha) { - sorter.sort(&elements[max_elements - alpha_element_count], alpha_element_count); - } else { - sorter.sort(elements, element_count); - } - } - - struct SortByDepth { - - _FORCE_INLINE_ bool operator()(const Element *A, const Element *B) const { - return A->instance->depth < B->instance->depth; - } - }; - - void sort_by_depth(bool p_alpha) { //used for shadows - - SortArray<Element *, SortByDepth> sorter; - if (p_alpha) { - sorter.sort(&elements[max_elements - alpha_element_count], alpha_element_count); - } else { - sorter.sort(elements, element_count); - } - } - - struct SortByReverseDepthAndPriority { - - _FORCE_INLINE_ bool operator()(const Element *A, const Element *B) const { - uint32_t layer_A = uint32_t(A->sort_key >> SORT_KEY_PRIORITY_SHIFT); - uint32_t layer_B = uint32_t(B->sort_key >> SORT_KEY_PRIORITY_SHIFT); - if (layer_A == layer_B) { - return A->instance->depth > B->instance->depth; - } else { - return layer_A < layer_B; - } - } - }; - - void sort_by_reverse_depth_and_priority(bool p_alpha) { //used for alpha - - SortArray<Element *, SortByReverseDepthAndPriority> sorter; - if (p_alpha) { - sorter.sort(&elements[max_elements - alpha_element_count], alpha_element_count); - } else { - sorter.sort(elements, element_count); - } - } - - _FORCE_INLINE_ Element *add_element() { - - if (element_count + alpha_element_count >= max_elements) - return NULL; - elements[element_count] = &base_elements[element_count]; - return elements[element_count++]; - } - - _FORCE_INLINE_ Element *add_alpha_element() { - - if (element_count + alpha_element_count >= max_elements) - return NULL; - int idx = max_elements - alpha_element_count - 1; - elements[idx] = &base_elements[idx]; - alpha_element_count++; - return elements[idx]; - } - - void init() { - - element_count = 0; - alpha_element_count = 0; - elements = memnew_arr(Element *, max_elements); - base_elements = memnew_arr(Element, max_elements); - for (int i = 0; i < max_elements; i++) - elements[i] = &base_elements[i]; // assign elements - } - - RenderList() { - - max_elements = DEFAULT_MAX_ELEMENTS; - max_lights = DEFAULT_MAX_LIGHTS; - max_reflections = DEFAULT_MAX_REFLECTIONS; - } - - ~RenderList() { - memdelete_arr(elements); - memdelete_arr(base_elements); - } - }; - - LightInstance *directional_light; - LightInstance *directional_lights[RenderList::MAX_DIRECTIONAL_LIGHTS]; - - RenderList render_list; - - _FORCE_INLINE_ void _set_cull(bool p_front, bool p_disabled, bool p_reverse_cull); - - _FORCE_INLINE_ bool _setup_material(RasterizerStorageGLES3::Material *p_material, bool p_depth_pass, bool p_alpha_pass); - _FORCE_INLINE_ void _setup_geometry(RenderList::Element *e, const Transform &p_view_transform); - _FORCE_INLINE_ void _render_geometry(RenderList::Element *e); - _FORCE_INLINE_ void _setup_light(RenderList::Element *e, const Transform &p_view_transform); - - void _render_list(RenderList::Element **p_elements, int p_element_count, const Transform &p_view_transform, const CameraMatrix &p_projection, RasterizerStorageGLES3::Sky *p_sky, bool p_reverse_cull, bool p_alpha_pass, bool p_shadow, bool p_directional_add, bool p_directional_shadows); - - _FORCE_INLINE_ void _add_geometry(RasterizerStorageGLES3::Geometry *p_geometry, InstanceBase *p_instance, RasterizerStorageGLES3::GeometryOwner *p_owner, int p_material, bool p_depth_pass, bool p_shadow_pass); - - _FORCE_INLINE_ void _add_geometry_with_material(RasterizerStorageGLES3::Geometry *p_geometry, InstanceBase *p_instance, RasterizerStorageGLES3::GeometryOwner *p_owner, RasterizerStorageGLES3::Material *p_material, bool p_depth_pass, bool p_shadow_pass); - - void _draw_sky(RasterizerStorageGLES3::Sky *p_sky, const CameraMatrix &p_projection, const Transform &p_transform, bool p_vflip, float p_custom_fov, float p_energy, const Basis &p_sky_orientation); - - void _setup_environment(Environment *env, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, bool p_no_fog = false); - void _setup_directional_light(int p_index, const Transform &p_camera_inverse_transform, bool p_use_shadows); - void _setup_lights(RID *p_light_cull_result, int p_light_cull_count, const Transform &p_camera_inverse_transform, const CameraMatrix &p_camera_projection, RID p_shadow_atlas); - void _setup_reflections(RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, const Transform &p_camera_inverse_transform, const CameraMatrix &p_camera_projection, RID p_reflection_atlas, Environment *p_env); - - void _copy_screen(bool p_invalidate_color = false, bool p_invalidate_depth = false); - void _copy_texture_to_front_buffer(GLuint p_texture); //used for debug - - void _fill_render_list(InstanceBase **p_cull_result, int p_cull_count, bool p_depth_pass, bool p_shadow_pass); - - void _blur_effect_buffer(); - void _render_mrts(Environment *env, const CameraMatrix &p_cam_projection); - void _post_process(Environment *env, const CameraMatrix &p_cam_projection); - - void _prepare_depth_texture(); - void _bind_depth_texture(); - - virtual void render_scene(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID p_environment, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass); - virtual void render_shadow(RID p_light, RID p_shadow_atlas, int p_pass, InstanceBase **p_cull_result, int p_cull_count); - virtual bool free(RID p_rid); - - virtual void set_scene_pass(uint64_t p_pass); - virtual void set_debug_draw_mode(VS::ViewportDebugDraw p_debug_draw); - - void iteration(); - void initialize(); - void finalize(); - RasterizerSceneGLES3(); - ~RasterizerSceneGLES3(); -}; - -#endif // RASTERIZERSCENEGLES3_H diff --git a/drivers/gles3/rasterizer_storage_gles3.cpp b/drivers/gles3/rasterizer_storage_gles3.cpp deleted file mode 100644 index 6baf69dc7b..0000000000 --- a/drivers/gles3/rasterizer_storage_gles3.cpp +++ /dev/null @@ -1,8403 +0,0 @@ -/*************************************************************************/ -/* rasterizer_storage_gles3.cpp */ -/*************************************************************************/ -/* 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. */ -/*************************************************************************/ - -#include "rasterizer_storage_gles3.h" -#include "core/engine.h" -#include "core/project_settings.h" -#include "rasterizer_canvas_gles3.h" -#include "rasterizer_scene_gles3.h" - -/* TEXTURE API */ - -#define _EXT_COMPRESSED_RGB_PVRTC_4BPPV1_IMG 0x8C00 -#define _EXT_COMPRESSED_RGB_PVRTC_2BPPV1_IMG 0x8C01 -#define _EXT_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG 0x8C02 -#define _EXT_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG 0x8C03 - -#define _EXT_COMPRESSED_SRGB_PVRTC_2BPPV1_EXT 0x8A54 -#define _EXT_COMPRESSED_SRGB_PVRTC_4BPPV1_EXT 0x8A55 -#define _EXT_COMPRESSED_SRGB_ALPHA_PVRTC_2BPPV1_EXT 0x8A56 -#define _EXT_COMPRESSED_SRGB_ALPHA_PVRTC_4BPPV1_EXT 0x8A57 - -#define _EXT_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1 -#define _EXT_COMPRESSED_RGBA_S3TC_DXT3_EXT 0x83F2 -#define _EXT_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83F3 - -#define _EXT_COMPRESSED_LUMINANCE_LATC1_EXT 0x8C70 -#define _EXT_COMPRESSED_SIGNED_LUMINANCE_LATC1_EXT 0x8C71 -#define _EXT_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT 0x8C72 -#define _EXT_COMPRESSED_SIGNED_LUMINANCE_ALPHA_LATC2_EXT 0x8C73 - -#define _EXT_COMPRESSED_RED_RGTC1_EXT 0x8DBB -#define _EXT_COMPRESSED_RED_RGTC1 0x8DBB -#define _EXT_COMPRESSED_SIGNED_RED_RGTC1 0x8DBC -#define _EXT_COMPRESSED_RG_RGTC2 0x8DBD -#define _EXT_COMPRESSED_SIGNED_RG_RGTC2 0x8DBE -#define _EXT_COMPRESSED_SIGNED_RED_RGTC1_EXT 0x8DBC -#define _EXT_COMPRESSED_RED_GREEN_RGTC2_EXT 0x8DBD -#define _EXT_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT 0x8DBE -#define _EXT_ETC1_RGB8_OES 0x8D64 - -#define _EXT_SLUMINANCE_NV 0x8C46 -#define _EXT_SLUMINANCE_ALPHA_NV 0x8C44 -#define _EXT_SRGB8_NV 0x8C41 -#define _EXT_SLUMINANCE8_NV 0x8C47 -#define _EXT_SLUMINANCE8_ALPHA8_NV 0x8C45 - -#define _EXT_COMPRESSED_SRGB_S3TC_DXT1_NV 0x8C4C -#define _EXT_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_NV 0x8C4D -#define _EXT_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_NV 0x8C4E -#define _EXT_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_NV 0x8C4F - -#define _EXT_ATC_RGB_AMD 0x8C92 -#define _EXT_ATC_RGBA_EXPLICIT_ALPHA_AMD 0x8C93 -#define _EXT_ATC_RGBA_INTERPOLATED_ALPHA_AMD 0x87EE - -#define _EXT_TEXTURE_CUBE_MAP_SEAMLESS 0x884F - -#define _GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE -#define _GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF - -#define _EXT_COMPRESSED_R11_EAC 0x9270 -#define _EXT_COMPRESSED_SIGNED_R11_EAC 0x9271 -#define _EXT_COMPRESSED_RG11_EAC 0x9272 -#define _EXT_COMPRESSED_SIGNED_RG11_EAC 0x9273 -#define _EXT_COMPRESSED_RGB8_ETC2 0x9274 -#define _EXT_COMPRESSED_SRGB8_ETC2 0x9275 -#define _EXT_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 0x9276 -#define _EXT_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 0x9277 -#define _EXT_COMPRESSED_RGBA8_ETC2_EAC 0x9278 -#define _EXT_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC 0x9279 - -#define _EXT_COMPRESSED_RGBA_BPTC_UNORM 0x8E8C -#define _EXT_COMPRESSED_SRGB_ALPHA_BPTC_UNORM 0x8E8D -#define _EXT_COMPRESSED_RGB_BPTC_SIGNED_FLOAT 0x8E8E -#define _EXT_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT 0x8E8F - -#ifndef GLES_OVER_GL -#define glClearDepth glClearDepthf -#endif - -#ifdef __EMSCRIPTEN__ -#include <emscripten/emscripten.h> - -void glGetBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, GLvoid *data) { - - /* clang-format off */ - EM_ASM({ - GLctx.getBufferSubData($0, $1, HEAPU8, $2, $3); - }, target, offset, data, size); - /* clang-format on */ -} -#endif - -void glTexStorage2DCustom(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type) { - -#ifdef GLES_OVER_GL - - for (int i = 0; i < levels; i++) { - glTexImage2D(target, i, internalformat, width, height, 0, format, type, NULL); - width = MAX(1, (width / 2)); - height = MAX(1, (height / 2)); - } - -#else - glTexStorage2D(target, levels, internalformat, width, height); -#endif -} - -GLuint RasterizerStorageGLES3::system_fbo = 0; - -Ref<Image> RasterizerStorageGLES3::_get_gl_image_and_format(const Ref<Image> &p_image, Image::Format p_format, uint32_t p_flags, Image::Format &r_real_format, GLenum &r_gl_format, GLenum &r_gl_internal_format, GLenum &r_gl_type, bool &r_compressed, bool &r_srgb, bool p_force_decompress) const { - - r_compressed = false; - r_gl_format = 0; - r_real_format = p_format; - Ref<Image> image = p_image; - r_srgb = false; - - bool need_decompress = false; - - switch (p_format) { - - case Image::FORMAT_L8: { -#ifdef GLES_OVER_GL - r_gl_internal_format = GL_R8; - r_gl_format = GL_RED; - r_gl_type = GL_UNSIGNED_BYTE; -#else - r_gl_internal_format = GL_LUMINANCE; - r_gl_format = GL_LUMINANCE; - r_gl_type = GL_UNSIGNED_BYTE; -#endif - } break; - case Image::FORMAT_LA8: { -#ifdef GLES_OVER_GL - r_gl_internal_format = GL_RG8; - r_gl_format = GL_RG; - r_gl_type = GL_UNSIGNED_BYTE; -#else - r_gl_internal_format = GL_LUMINANCE_ALPHA; - r_gl_format = GL_LUMINANCE_ALPHA; - r_gl_type = GL_UNSIGNED_BYTE; -#endif - } break; - case Image::FORMAT_R8: { - - r_gl_internal_format = GL_R8; - r_gl_format = GL_RED; - r_gl_type = GL_UNSIGNED_BYTE; - - } break; - case Image::FORMAT_RG8: { - - r_gl_internal_format = GL_RG8; - r_gl_format = GL_RG; - r_gl_type = GL_UNSIGNED_BYTE; - - } break; - case Image::FORMAT_RGB8: { - - r_gl_internal_format = (config.srgb_decode_supported || (p_flags & VS::TEXTURE_FLAG_CONVERT_TO_LINEAR)) ? GL_SRGB8 : GL_RGB8; - r_gl_format = GL_RGB; - r_gl_type = GL_UNSIGNED_BYTE; - r_srgb = true; - - } break; - case Image::FORMAT_RGBA8: { - - r_gl_format = GL_RGBA; - r_gl_internal_format = (config.srgb_decode_supported || (p_flags & VS::TEXTURE_FLAG_CONVERT_TO_LINEAR)) ? GL_SRGB8_ALPHA8 : GL_RGBA8; - r_gl_type = GL_UNSIGNED_BYTE; - r_srgb = true; - - } break; - case Image::FORMAT_RGBA4444: { - - r_gl_internal_format = GL_RGBA4; - r_gl_format = GL_RGBA; - r_gl_type = GL_UNSIGNED_SHORT_4_4_4_4; - - } break; - case Image::FORMAT_RGBA5551: { - - r_gl_internal_format = GL_RGB5_A1; - r_gl_format = GL_RGBA; - r_gl_type = GL_UNSIGNED_SHORT_5_5_5_1; - - } break; - case Image::FORMAT_RF: { - - r_gl_internal_format = GL_R32F; - r_gl_format = GL_RED; - r_gl_type = GL_FLOAT; - - } break; - case Image::FORMAT_RGF: { - - r_gl_internal_format = GL_RG32F; - r_gl_format = GL_RG; - r_gl_type = GL_FLOAT; - - } break; - case Image::FORMAT_RGBF: { - - r_gl_internal_format = GL_RGB32F; - r_gl_format = GL_RGB; - r_gl_type = GL_FLOAT; - - } break; - case Image::FORMAT_RGBAF: { - - r_gl_internal_format = GL_RGBA32F; - r_gl_format = GL_RGBA; - r_gl_type = GL_FLOAT; - - } break; - case Image::FORMAT_RH: { - r_gl_internal_format = GL_R32F; - r_gl_format = GL_RED; - r_gl_type = GL_HALF_FLOAT; - } break; - case Image::FORMAT_RGH: { - r_gl_internal_format = GL_RG32F; - r_gl_format = GL_RG; - r_gl_type = GL_HALF_FLOAT; - - } break; - case Image::FORMAT_RGBH: { - r_gl_internal_format = GL_RGB32F; - r_gl_format = GL_RGB; - r_gl_type = GL_HALF_FLOAT; - - } break; - case Image::FORMAT_RGBAH: { - r_gl_internal_format = GL_RGBA32F; - r_gl_format = GL_RGBA; - r_gl_type = GL_HALF_FLOAT; - - } break; - case Image::FORMAT_RGBE9995: { - r_gl_internal_format = GL_RGB9_E5; - r_gl_format = GL_RGB; - r_gl_type = GL_UNSIGNED_INT_5_9_9_9_REV; - - } break; - case Image::FORMAT_DXT1: { - - if (config.s3tc_supported) { - - r_gl_internal_format = (config.srgb_decode_supported || (p_flags & VS::TEXTURE_FLAG_CONVERT_TO_LINEAR)) ? _EXT_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_NV : _EXT_COMPRESSED_RGBA_S3TC_DXT1_EXT; - r_gl_format = GL_RGBA; - r_gl_type = GL_UNSIGNED_BYTE; - r_compressed = true; - r_srgb = true; - - } else { - - need_decompress = true; - } - - } break; - case Image::FORMAT_DXT3: { - - if (config.s3tc_supported) { - - r_gl_internal_format = (config.srgb_decode_supported || (p_flags & VS::TEXTURE_FLAG_CONVERT_TO_LINEAR)) ? _EXT_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_NV : _EXT_COMPRESSED_RGBA_S3TC_DXT3_EXT; - r_gl_format = GL_RGBA; - r_gl_type = GL_UNSIGNED_BYTE; - r_compressed = true; - r_srgb = true; - - } else { - - need_decompress = true; - } - - } break; - case Image::FORMAT_DXT5: { - - if (config.s3tc_supported) { - - r_gl_internal_format = (config.srgb_decode_supported || (p_flags & VS::TEXTURE_FLAG_CONVERT_TO_LINEAR)) ? _EXT_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_NV : _EXT_COMPRESSED_RGBA_S3TC_DXT5_EXT; - r_gl_format = GL_RGBA; - r_gl_type = GL_UNSIGNED_BYTE; - r_compressed = true; - r_srgb = true; - - } else { - - need_decompress = true; - } - - } break; - case Image::FORMAT_RGTC_R: { - - if (config.rgtc_supported) { - - r_gl_internal_format = _EXT_COMPRESSED_RED_RGTC1_EXT; - r_gl_format = GL_RGBA; - r_gl_type = GL_UNSIGNED_BYTE; - r_compressed = true; - - } else { - - need_decompress = true; - } - - } break; - case Image::FORMAT_RGTC_RG: { - - if (config.rgtc_supported) { - - r_gl_internal_format = _EXT_COMPRESSED_RED_GREEN_RGTC2_EXT; - r_gl_format = GL_RGBA; - r_gl_type = GL_UNSIGNED_BYTE; - r_compressed = true; - } else { - - need_decompress = true; - } - - } break; - case Image::FORMAT_BPTC_RGBA: { - - if (config.bptc_supported) { - - r_gl_internal_format = (config.srgb_decode_supported || (p_flags & VS::TEXTURE_FLAG_CONVERT_TO_LINEAR)) ? _EXT_COMPRESSED_SRGB_ALPHA_BPTC_UNORM : _EXT_COMPRESSED_RGBA_BPTC_UNORM; - r_gl_format = GL_RGBA; - r_gl_type = GL_UNSIGNED_BYTE; - r_compressed = true; - r_srgb = true; - - } else { - - need_decompress = true; - } - } break; - case Image::FORMAT_BPTC_RGBF: { - - if (config.bptc_supported) { - - r_gl_internal_format = _EXT_COMPRESSED_RGB_BPTC_SIGNED_FLOAT; - r_gl_format = GL_RGB; - r_gl_type = GL_FLOAT; - r_compressed = true; - } else { - - need_decompress = true; - } - } break; - case Image::FORMAT_BPTC_RGBFU: { - if (config.bptc_supported) { - - r_gl_internal_format = _EXT_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT; - r_gl_format = GL_RGB; - r_gl_type = GL_FLOAT; - r_compressed = true; - } else { - - need_decompress = true; - } - } break; - case Image::FORMAT_PVRTC2: { - - if (config.pvrtc_supported) { - - r_gl_internal_format = (config.srgb_decode_supported || (p_flags & VS::TEXTURE_FLAG_CONVERT_TO_LINEAR)) ? _EXT_COMPRESSED_SRGB_PVRTC_2BPPV1_EXT : _EXT_COMPRESSED_RGB_PVRTC_2BPPV1_IMG; - r_gl_format = GL_RGBA; - r_gl_type = GL_UNSIGNED_BYTE; - r_compressed = true; - r_srgb = true; - - } else { - - need_decompress = true; - } - } break; - case Image::FORMAT_PVRTC2A: { - - if (config.pvrtc_supported) { - - r_gl_internal_format = (config.srgb_decode_supported || (p_flags & VS::TEXTURE_FLAG_CONVERT_TO_LINEAR)) ? _EXT_COMPRESSED_SRGB_ALPHA_PVRTC_2BPPV1_EXT : _EXT_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG; - r_gl_format = GL_RGBA; - r_gl_type = GL_UNSIGNED_BYTE; - r_compressed = true; - r_srgb = true; - - } else { - - need_decompress = true; - } - - } break; - case Image::FORMAT_PVRTC4: { - - if (config.pvrtc_supported) { - - r_gl_internal_format = (config.srgb_decode_supported || (p_flags & VS::TEXTURE_FLAG_CONVERT_TO_LINEAR)) ? _EXT_COMPRESSED_SRGB_PVRTC_4BPPV1_EXT : _EXT_COMPRESSED_RGB_PVRTC_4BPPV1_IMG; - r_gl_format = GL_RGBA; - r_gl_type = GL_UNSIGNED_BYTE; - r_compressed = true; - r_srgb = true; - - } else { - - need_decompress = true; - } - - } break; - case Image::FORMAT_PVRTC4A: { - - if (config.pvrtc_supported) { - - r_gl_internal_format = (config.srgb_decode_supported || (p_flags & VS::TEXTURE_FLAG_CONVERT_TO_LINEAR)) ? _EXT_COMPRESSED_SRGB_ALPHA_PVRTC_4BPPV1_EXT : _EXT_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG; - r_gl_format = GL_RGBA; - r_gl_type = GL_UNSIGNED_BYTE; - r_compressed = true; - r_srgb = true; - - } else { - - need_decompress = true; - } - - } break; - case Image::FORMAT_ETC: { - - if (config.etc_supported) { - - r_gl_internal_format = _EXT_ETC1_RGB8_OES; - r_gl_format = GL_RGBA; - r_gl_type = GL_UNSIGNED_BYTE; - r_compressed = true; - - } else { - - need_decompress = true; - } - - } break; - case Image::FORMAT_ETC2_R11: { - - if (config.etc2_supported) { - - r_gl_internal_format = _EXT_COMPRESSED_R11_EAC; - r_gl_format = GL_RED; - r_gl_type = GL_UNSIGNED_BYTE; - r_compressed = true; - - } else { - - need_decompress = true; - } - } break; - case Image::FORMAT_ETC2_R11S: { - - if (config.etc2_supported) { - - r_gl_internal_format = _EXT_COMPRESSED_SIGNED_R11_EAC; - r_gl_format = GL_RED; - r_gl_type = GL_UNSIGNED_BYTE; - r_compressed = true; - - } else { - - need_decompress = true; - } - } break; - case Image::FORMAT_ETC2_RG11: { - - if (config.etc2_supported) { - - r_gl_internal_format = _EXT_COMPRESSED_RG11_EAC; - r_gl_format = GL_RG; - r_gl_type = GL_UNSIGNED_BYTE; - r_compressed = true; - - } else { - - need_decompress = true; - } - } break; - case Image::FORMAT_ETC2_RG11S: { - if (config.etc2_supported) { - - r_gl_internal_format = _EXT_COMPRESSED_SIGNED_RG11_EAC; - r_gl_format = GL_RG; - r_gl_type = GL_UNSIGNED_BYTE; - r_compressed = true; - - } else { - need_decompress = true; - } - } break; - case Image::FORMAT_ETC2_RGB8: { - - if (config.etc2_supported) { - - r_gl_internal_format = (config.srgb_decode_supported || (p_flags & VS::TEXTURE_FLAG_CONVERT_TO_LINEAR)) ? _EXT_COMPRESSED_SRGB8_ETC2 : _EXT_COMPRESSED_RGB8_ETC2; - r_gl_format = GL_RGB; - r_gl_type = GL_UNSIGNED_BYTE; - r_compressed = true; - r_srgb = true; - - } else { - - need_decompress = true; - } - } break; - case Image::FORMAT_ETC2_RGBA8: { - - if (config.etc2_supported) { - - r_gl_internal_format = (config.srgb_decode_supported || (p_flags & VS::TEXTURE_FLAG_CONVERT_TO_LINEAR)) ? _EXT_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC : _EXT_COMPRESSED_RGBA8_ETC2_EAC; - r_gl_format = GL_RGBA; - r_gl_type = GL_UNSIGNED_BYTE; - r_compressed = true; - r_srgb = true; - - } else { - - need_decompress = true; - } - } break; - case Image::FORMAT_ETC2_RGB8A1: { - - if (config.etc2_supported) { - - r_gl_internal_format = (config.srgb_decode_supported || (p_flags & VS::TEXTURE_FLAG_CONVERT_TO_LINEAR)) ? _EXT_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 : _EXT_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2; - r_gl_format = GL_RGBA; - r_gl_type = GL_UNSIGNED_BYTE; - r_compressed = true; - r_srgb = true; - - } else { - - need_decompress = true; - } - } break; - default: { - - ERR_FAIL_V(Ref<Image>()); - } - } - - if (need_decompress || p_force_decompress) { - - if (!image.is_null()) { - image = image->duplicate(); - image->decompress(); - ERR_FAIL_COND_V(image->is_compressed(), image); - image->convert(Image::FORMAT_RGBA8); - } - - r_gl_format = GL_RGBA; - r_gl_internal_format = (config.srgb_decode_supported || (p_flags & VS::TEXTURE_FLAG_CONVERT_TO_LINEAR)) ? GL_SRGB8_ALPHA8 : GL_RGBA8; - r_gl_type = GL_UNSIGNED_BYTE; - r_compressed = false; - r_real_format = Image::FORMAT_RGBA8; - r_srgb = true; - - return image; - } - - return image; -} - -static const GLenum _cube_side_enum[6] = { - - GL_TEXTURE_CUBE_MAP_NEGATIVE_X, - GL_TEXTURE_CUBE_MAP_POSITIVE_X, - GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, - GL_TEXTURE_CUBE_MAP_POSITIVE_Y, - GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, - GL_TEXTURE_CUBE_MAP_POSITIVE_Z, - -}; - -RID RasterizerStorageGLES3::texture_create() { - - Texture *texture = memnew(Texture); - ERR_FAIL_COND_V(!texture, RID()); - glGenTextures(1, &texture->tex_id); - texture->active = false; - texture->total_data_size = 0; - - return texture_owner.make_rid(texture); -} - -void RasterizerStorageGLES3::texture_allocate(RID p_texture, int p_width, int p_height, int p_depth_3d, Image::Format p_format, VisualServer::TextureType p_type, uint32_t p_flags) { - - GLenum format; - GLenum internal_format; - GLenum type; - - bool compressed; - bool srgb; - - if (p_flags & VS::TEXTURE_FLAG_USED_FOR_STREAMING) { - p_flags &= ~VS::TEXTURE_FLAG_MIPMAPS; // no mipies for video - } - -#ifndef GLES_OVER_GL - switch (p_format) { - case Image::FORMAT_RF: - case Image::FORMAT_RGF: - case Image::FORMAT_RGBF: - case Image::FORMAT_RGBAF: - case Image::FORMAT_RH: - case Image::FORMAT_RGH: - case Image::FORMAT_RGBH: - case Image::FORMAT_RGBAH: { - if (!config.texture_float_linear_supported) { - // disable linear texture filtering when not supported for float format on some devices (issue #24295) - p_flags &= ~VS::TEXTURE_FLAG_FILTER; - } - } break; - default: { - } - } -#endif - - Texture *texture = texture_owner.get(p_texture); - ERR_FAIL_COND(!texture); - texture->width = p_width; - texture->height = p_height; - texture->depth = p_depth_3d; - texture->format = p_format; - texture->flags = p_flags; - texture->stored_cube_sides = 0; - - texture->type = p_type; - - switch (p_type) { - case VS::TEXTURE_TYPE_2D: { - texture->target = GL_TEXTURE_2D; - texture->images.resize(1); - } break; - case VS::TEXTURE_TYPE_CUBEMAP: { - texture->target = GL_TEXTURE_CUBE_MAP; - texture->images.resize(6); - } break; - case VS::TEXTURE_TYPE_2D_ARRAY: { - texture->target = GL_TEXTURE_2D_ARRAY; - texture->images.resize(p_depth_3d); - } break; - case VS::TEXTURE_TYPE_3D: { - texture->target = GL_TEXTURE_3D; - texture->images.resize(p_depth_3d); - } break; - } - - texture->is_npot_repeat_mipmap = false; -#ifdef JAVASCRIPT_ENABLED - // WebGL 2.0 on browsers does not seem to properly support compressed non power-of-two (NPOT) - // textures with repeat/mipmaps, even though NPOT textures should be supported as per the spec. - // Force decompressing them to work it around on WebGL 2.0 at a performance cost (GH-33058). - int po2_width = next_power_of_2(p_width); - int po2_height = next_power_of_2(p_height); - bool is_po2 = p_width == po2_width && p_height == po2_height; - - if (!is_po2 && (p_flags & VS::TEXTURE_FLAG_REPEAT || p_flags & VS::TEXTURE_FLAG_MIPMAPS)) { - texture->is_npot_repeat_mipmap = true; - } -#endif // JAVASCRIPT_ENABLED - - Image::Format real_format; - _get_gl_image_and_format(Ref<Image>(), texture->format, texture->flags, real_format, format, internal_format, type, compressed, srgb, texture->is_npot_repeat_mipmap); - - texture->alloc_width = texture->width; - texture->alloc_height = texture->height; - texture->alloc_depth = texture->depth; - - texture->gl_format_cache = format; - texture->gl_type_cache = type; - texture->gl_internal_format_cache = internal_format; - texture->compressed = compressed; - texture->srgb = srgb; - texture->data_size = 0; - texture->mipmaps = 1; - - glActiveTexture(GL_TEXTURE0); - glBindTexture(texture->target, texture->tex_id); - - if (p_type == VS::TEXTURE_TYPE_3D || p_type == VS::TEXTURE_TYPE_2D_ARRAY) { - - int width = p_width; - int height = p_height; - int depth = p_depth_3d; - - int mipmaps = 0; - - while (width > 0 || height > 0 || (p_type == VS::TEXTURE_TYPE_3D && depth > 0)) { - width = MAX(1, width); - height = MAX(1, height); - depth = MAX(1, depth); - - glTexImage3D(texture->target, mipmaps, internal_format, width, height, depth, 0, format, type, NULL); - - width /= 2; - height /= 2; - - if (p_type == VS::TEXTURE_TYPE_3D) { - depth /= 2; - } - - mipmaps++; - - if (!(p_flags & VS::TEXTURE_FLAG_MIPMAPS)) - break; - } - - glTexParameteri(texture->target, GL_TEXTURE_BASE_LEVEL, 0); - glTexParameteri(texture->target, GL_TEXTURE_MAX_LEVEL, mipmaps - 1); - - } else if (p_flags & VS::TEXTURE_FLAG_USED_FOR_STREAMING) { - //prealloc if video - glTexImage2D(texture->target, 0, internal_format, p_width, p_height, 0, format, type, NULL); - } - - texture->active = true; -} - -void RasterizerStorageGLES3::texture_set_data(RID p_texture, const Ref<Image> &p_image, int p_layer) { - - Texture *texture = texture_owner.get(p_texture); - - ERR_FAIL_COND(!texture); - ERR_FAIL_COND(!texture->active); - ERR_FAIL_COND(texture->render_target); - ERR_FAIL_COND(texture->format != p_image->get_format()); - ERR_FAIL_COND(p_image.is_null()); - - GLenum type; - GLenum format; - GLenum internal_format; - bool compressed; - bool srgb; - - if (config.keep_original_textures && !(texture->flags & VS::TEXTURE_FLAG_USED_FOR_STREAMING)) { - texture->images.write[p_layer] = p_image; - } - - Image::Format real_format; - Ref<Image> img = _get_gl_image_and_format(p_image, p_image->get_format(), texture->flags, real_format, format, internal_format, type, compressed, srgb, texture->is_npot_repeat_mipmap); - - if (config.shrink_textures_x2 && (p_image->has_mipmaps() || !p_image->is_compressed()) && !(texture->flags & VS::TEXTURE_FLAG_USED_FOR_STREAMING)) { - - texture->alloc_height = MAX(1, texture->alloc_height / 2); - texture->alloc_width = MAX(1, texture->alloc_width / 2); - - if (texture->alloc_width == img->get_width() / 2 && texture->alloc_height == img->get_height() / 2) { - - img->shrink_x2(); - } else if (img->get_format() <= Image::FORMAT_RGBA8) { - - img->resize(texture->alloc_width, texture->alloc_height, Image::INTERPOLATE_BILINEAR); - } - }; - - GLenum blit_target = GL_TEXTURE_2D; - - switch (texture->type) { - case VS::TEXTURE_TYPE_2D: { - blit_target = GL_TEXTURE_2D; - } break; - case VS::TEXTURE_TYPE_CUBEMAP: { - ERR_FAIL_INDEX(p_layer, 6); - blit_target = _cube_side_enum[p_layer]; - } break; - case VS::TEXTURE_TYPE_2D_ARRAY: { - blit_target = GL_TEXTURE_2D_ARRAY; - } break; - case VS::TEXTURE_TYPE_3D: { - blit_target = GL_TEXTURE_3D; - } break; - } - - texture->data_size = img->get_data().size(); - PoolVector<uint8_t>::Read read = img->get_data().read(); - ERR_FAIL_COND(!read.ptr()); - - glActiveTexture(GL_TEXTURE0); - glBindTexture(texture->target, texture->tex_id); - - texture->ignore_mipmaps = compressed && !img->has_mipmaps(); - - if ((texture->flags & VS::TEXTURE_FLAG_MIPMAPS) && !texture->ignore_mipmaps) - glTexParameteri(texture->target, GL_TEXTURE_MIN_FILTER, config.use_fast_texture_filter ? GL_LINEAR_MIPMAP_NEAREST : GL_LINEAR_MIPMAP_LINEAR); - else { - if (texture->flags & VS::TEXTURE_FLAG_FILTER) { - glTexParameteri(texture->target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - } else { - glTexParameteri(texture->target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - } - } - - if (config.srgb_decode_supported && srgb) { - - if (texture->flags & VS::TEXTURE_FLAG_CONVERT_TO_LINEAR) { - - glTexParameteri(texture->target, _TEXTURE_SRGB_DECODE_EXT, _DECODE_EXT); - texture->using_srgb = true; - } else { - glTexParameteri(texture->target, _TEXTURE_SRGB_DECODE_EXT, _SKIP_DECODE_EXT); - texture->using_srgb = false; - } - } - - if (texture->flags & VS::TEXTURE_FLAG_FILTER) { - - glTexParameteri(texture->target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // Linear Filtering - - } else { - - glTexParameteri(texture->target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); // raw Filtering - } - - if (((texture->flags & VS::TEXTURE_FLAG_REPEAT) || (texture->flags & VS::TEXTURE_FLAG_MIRRORED_REPEAT)) && texture->target != GL_TEXTURE_CUBE_MAP) { - - if (texture->flags & VS::TEXTURE_FLAG_MIRRORED_REPEAT) { - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT); - } else { - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - } - } else { - - //glTexParameterf( texture->target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE ); - glTexParameterf(texture->target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameterf(texture->target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - } - -//set swizle for older format compatibility -#ifdef GLES_OVER_GL - switch (texture->format) { - - case Image::FORMAT_L8: { - glTexParameteri(texture->target, GL_TEXTURE_SWIZZLE_R, GL_RED); - glTexParameteri(texture->target, GL_TEXTURE_SWIZZLE_G, GL_RED); - glTexParameteri(texture->target, GL_TEXTURE_SWIZZLE_B, GL_RED); - glTexParameteri(texture->target, GL_TEXTURE_SWIZZLE_A, GL_ONE); - - } break; - case Image::FORMAT_LA8: { - - glTexParameteri(texture->target, GL_TEXTURE_SWIZZLE_R, GL_RED); - glTexParameteri(texture->target, GL_TEXTURE_SWIZZLE_G, GL_RED); - glTexParameteri(texture->target, GL_TEXTURE_SWIZZLE_B, GL_RED); - glTexParameteri(texture->target, GL_TEXTURE_SWIZZLE_A, GL_GREEN); - } break; - default: { - glTexParameteri(texture->target, GL_TEXTURE_SWIZZLE_R, GL_RED); - glTexParameteri(texture->target, GL_TEXTURE_SWIZZLE_G, GL_GREEN); - glTexParameteri(texture->target, GL_TEXTURE_SWIZZLE_B, GL_BLUE); - glTexParameteri(texture->target, GL_TEXTURE_SWIZZLE_A, GL_ALPHA); - - } break; - } -#endif - if (config.use_anisotropic_filter) { - - if (texture->flags & VS::TEXTURE_FLAG_ANISOTROPIC_FILTER) { - - glTexParameterf(texture->target, _GL_TEXTURE_MAX_ANISOTROPY_EXT, config.anisotropic_level); - } else { - glTexParameterf(texture->target, _GL_TEXTURE_MAX_ANISOTROPY_EXT, 1); - } - } - - int mipmaps = ((texture->flags & VS::TEXTURE_FLAG_MIPMAPS) && img->has_mipmaps()) ? img->get_mipmap_count() + 1 : 1; - - int w = img->get_width(); - int h = img->get_height(); - - int tsize = 0; - - for (int i = 0; i < mipmaps; i++) { - - int size, ofs; - img->get_mipmap_offset_and_size(i, ofs, size); - - if (texture->type == VS::TEXTURE_TYPE_2D || texture->type == VS::TEXTURE_TYPE_CUBEMAP) { - - if (texture->compressed) { - glPixelStorei(GL_UNPACK_ALIGNMENT, 4); - - int bw = w; - int bh = h; - - glCompressedTexImage2D(blit_target, i, internal_format, bw, bh, 0, size, &read[ofs]); - - } else { - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - if (texture->flags & VS::TEXTURE_FLAG_USED_FOR_STREAMING) { - glTexSubImage2D(blit_target, i, 0, 0, w, h, format, type, &read[ofs]); - } else { - glTexImage2D(blit_target, i, internal_format, w, h, 0, format, type, &read[ofs]); - } - } - } else { - if (texture->compressed) { - glPixelStorei(GL_UNPACK_ALIGNMENT, 4); - - int bw = w; - int bh = h; - - glCompressedTexSubImage3D(blit_target, i, 0, 0, p_layer, bw, bh, 1, internal_format, size, &read[ofs]); - } else { - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - - glTexSubImage3D(blit_target, i, 0, 0, p_layer, w, h, 1, format, type, &read[ofs]); - } - } - tsize += size; - - w = MAX(1, w >> 1); - h = MAX(1, h >> 1); - } - - // Handle array and 3D textures, as those set their data per layer. - tsize *= MAX(texture->alloc_depth, 1); - - info.texture_mem -= texture->total_data_size; - texture->total_data_size = tsize; - info.texture_mem += texture->total_data_size; - - //printf("texture: %i x %i - size: %i - total: %i\n",texture->width,texture->height,tsize,_rinfo.texture_mem); - - texture->stored_cube_sides |= (1 << p_layer); - - if ((texture->type == VS::TEXTURE_TYPE_2D || texture->type == VS::TEXTURE_TYPE_CUBEMAP) && (texture->flags & VS::TEXTURE_FLAG_MIPMAPS) && mipmaps == 1 && !texture->ignore_mipmaps && (texture->type != VS::TEXTURE_TYPE_CUBEMAP || texture->stored_cube_sides == (1 << 6) - 1)) { - //generate mipmaps if they were requested and the image does not contain them - glGenerateMipmap(texture->target); - } else if (mipmaps > 1) { - glTexParameteri(texture->target, GL_TEXTURE_BASE_LEVEL, 0); - glTexParameteri(texture->target, GL_TEXTURE_MAX_LEVEL, mipmaps - 1); - } else { - glTexParameteri(texture->target, GL_TEXTURE_BASE_LEVEL, 0); - glTexParameteri(texture->target, GL_TEXTURE_MAX_LEVEL, 0); - } - - texture->mipmaps = mipmaps; - - //texture_set_flags(p_texture,texture->flags); -} - -// Uploads pixel data to a sub-region of a texture, for the specified mipmap. -// The texture pixels must have been allocated before, because most features seen in texture_set_data() make no sense in a partial update. -// TODO If we want this to be usable without pre-filling pixels with a full image, we have to call glTexImage2D() with null data. -void RasterizerStorageGLES3::texture_set_data_partial(RID p_texture, const Ref<Image> &p_image, int src_x, int src_y, int src_w, int src_h, int dst_x, int dst_y, int p_dst_mip, int p_layer) { - - Texture *texture = texture_owner.get(p_texture); - - ERR_FAIL_COND(!texture); - ERR_FAIL_COND(!texture->active); - ERR_FAIL_COND(texture->render_target); - ERR_FAIL_COND(texture->format != p_image->get_format()); - ERR_FAIL_COND(p_image.is_null()); - ERR_FAIL_COND(src_w <= 0 || src_h <= 0); - ERR_FAIL_COND(src_x < 0 || src_y < 0 || src_x + src_w > p_image->get_width() || src_y + src_h > p_image->get_height()); - ERR_FAIL_COND(dst_x < 0 || dst_y < 0 || dst_x + src_w > texture->alloc_width || dst_y + src_h > texture->alloc_height); - ERR_FAIL_COND(p_dst_mip < 0 || p_dst_mip >= texture->mipmaps); - - GLenum type; - GLenum format; - GLenum internal_format; - bool compressed; - bool srgb; - - // Because OpenGL wants data as a dense array, we have to extract the sub-image if the source rect isn't the full image - Ref<Image> p_sub_img = p_image; - if (src_x > 0 || src_y > 0 || src_w != p_image->get_width() || src_h != p_image->get_height()) { - p_sub_img = p_image->get_rect(Rect2(src_x, src_y, src_w, src_h)); - } - - Image::Format real_format; - Ref<Image> img = _get_gl_image_and_format(p_sub_img, p_sub_img->get_format(), texture->flags, real_format, format, internal_format, type, compressed, srgb, texture->is_npot_repeat_mipmap); - - GLenum blit_target = GL_TEXTURE_2D; - - switch (texture->type) { - case VS::TEXTURE_TYPE_2D: { - blit_target = GL_TEXTURE_2D; - } break; - case VS::TEXTURE_TYPE_CUBEMAP: { - ERR_FAIL_INDEX(p_layer, 6); - blit_target = _cube_side_enum[p_layer]; - } break; - case VS::TEXTURE_TYPE_2D_ARRAY: { - blit_target = GL_TEXTURE_2D_ARRAY; - } break; - case VS::TEXTURE_TYPE_3D: { - blit_target = GL_TEXTURE_3D; - } break; - } - - PoolVector<uint8_t>::Read read = img->get_data().read(); - - glActiveTexture(GL_TEXTURE0); - glBindTexture(texture->target, texture->tex_id); - - int src_data_size = img->get_data().size(); - int src_ofs = 0; - - if (texture->type == VS::TEXTURE_TYPE_2D || texture->type == VS::TEXTURE_TYPE_CUBEMAP) { - if (texture->compressed) { - glPixelStorei(GL_UNPACK_ALIGNMENT, 4); - glCompressedTexSubImage2D(blit_target, p_dst_mip, dst_x, dst_y, src_w, src_h, internal_format, src_data_size, &read[src_ofs]); - - } else { - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - // `format` has to match the internal_format used when the texture was created - glTexSubImage2D(blit_target, p_dst_mip, dst_x, dst_y, src_w, src_h, format, type, &read[src_ofs]); - } - } else { - if (texture->compressed) { - glPixelStorei(GL_UNPACK_ALIGNMENT, 4); - glCompressedTexSubImage3D(blit_target, p_dst_mip, dst_x, dst_y, p_layer, src_w, src_h, 1, format, src_data_size, &read[src_ofs]); - } else { - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - // `format` has to match the internal_format used when the texture was created - glTexSubImage3D(blit_target, p_dst_mip, dst_x, dst_y, p_layer, src_w, src_h, 1, format, type, &read[src_ofs]); - } - } - - if (texture->flags & VS::TEXTURE_FLAG_FILTER) { - - glTexParameteri(texture->target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // Linear Filtering - - } else { - - glTexParameteri(texture->target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); // raw Filtering - } -} - -Ref<Image> RasterizerStorageGLES3::texture_get_data(RID p_texture, int p_layer) const { - - Texture *texture = texture_owner.get(p_texture); - - ERR_FAIL_COND_V(!texture, Ref<Image>()); - ERR_FAIL_COND_V(!texture->active, Ref<Image>()); - ERR_FAIL_COND_V(texture->data_size == 0 && !texture->render_target, Ref<Image>()); - - if (texture->type == VS::TEXTURE_TYPE_CUBEMAP && p_layer < 6 && !texture->images[p_layer].is_null()) { - return texture->images[p_layer]; - } - - // 3D textures and 2D texture arrays need special treatment, as the glGetTexImage reads **the whole** - // texture to host-memory. 3D textures and 2D texture arrays are potentially very big, so reading - // everything just to throw everything but one layer away is A Bad Idea. - // - // Unfortunately, to solve this, the copy shader has to read the data out via a shader and store it - // in a temporary framebuffer. The data from the framebuffer can then be read using glReadPixels. - if (texture->type == VS::TEXTURE_TYPE_2D_ARRAY || texture->type == VS::TEXTURE_TYPE_3D) { - // can't read a layer that doesn't exist - ERR_FAIL_INDEX_V(p_layer, texture->alloc_depth, Ref<Image>()); - - // get some information about the texture - Image::Format real_format; - GLenum gl_format; - GLenum gl_internal_format; - GLenum gl_type; - - bool compressed; - bool srgb; - - _get_gl_image_and_format( - Ref<Image>(), - texture->format, - texture->flags, - real_format, - gl_format, - gl_internal_format, - gl_type, - compressed, - srgb, - texture->is_npot_repeat_mipmap); - - PoolVector<uint8_t> data; - - // TODO need to decide between RgbaUnorm and RgbaFloat32 for output - int data_size = Image::get_image_data_size(texture->alloc_width, texture->alloc_height, Image::FORMAT_RGBA8, false); - - data.resize(data_size * 2); // add some more memory at the end, just in case for buggy drivers - PoolVector<uint8_t>::Write wb = data.write(); - - // generate temporary resources - GLuint tmp_fbo; - glGenFramebuffers(1, &tmp_fbo); - - GLuint tmp_color_attachment; - glGenTextures(1, &tmp_color_attachment); - - // now bring the OpenGL context into the correct state - { - glBindFramebuffer(GL_FRAMEBUFFER, tmp_fbo); - - // back color attachment with memory, then set properties - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, tmp_color_attachment); - // TODO support HDR properly - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture->alloc_width, texture->alloc_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - - // use the color texture as color attachment for this render pass - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tmp_color_attachment, 0); - - // more GL state, wheeeey - glDepthMask(GL_FALSE); - glDisable(GL_DEPTH_TEST); - glDisable(GL_CULL_FACE); - glDisable(GL_BLEND); - glDepthFunc(GL_LEQUAL); - glColorMask(1, 1, 1, 1); - - // use volume tex for reading - glActiveTexture(GL_TEXTURE0); - glBindTexture(texture->target, texture->tex_id); - - glViewport(0, 0, texture->alloc_width, texture->alloc_height); - - // set up copy shader for proper use - shaders.copy.set_conditional(CopyShaderGLES3::LINEAR_TO_SRGB, !srgb); - shaders.copy.set_conditional(CopyShaderGLES3::USE_TEXTURE3D, texture->type == VS::TEXTURE_TYPE_3D); - shaders.copy.set_conditional(CopyShaderGLES3::USE_TEXTURE2DARRAY, texture->type == VS::TEXTURE_TYPE_2D_ARRAY); - shaders.copy.bind(); - - float layer; - if (texture->type == VS::TEXTURE_TYPE_2D_ARRAY) - layer = (float)p_layer; - else - // calculate the normalized z coordinate for the layer - layer = (float)p_layer / (float)texture->alloc_depth; - - shaders.copy.set_uniform(CopyShaderGLES3::LAYER, layer); - - glBindVertexArray(resources.quadie_array); - } - - // clear color attachment, then perform copy - glClearColor(0.0, 0.0, 0.0, 0.0); - glClear(GL_COLOR_BUFFER_BIT); - - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - - // read the image into the host buffer - glReadPixels(0, 0, texture->alloc_width, texture->alloc_height, GL_RGBA, GL_UNSIGNED_BYTE, &wb[0]); - - // remove temp resources and unset some GL state - { - shaders.copy.set_conditional(CopyShaderGLES3::USE_TEXTURE3D, false); - shaders.copy.set_conditional(CopyShaderGLES3::USE_TEXTURE2DARRAY, false); - shaders.copy.set_conditional(CopyShaderGLES3::LINEAR_TO_SRGB, false); - - glBindFramebuffer(GL_FRAMEBUFFER, 0); - - glDeleteTextures(1, &tmp_color_attachment); - glDeleteFramebuffers(1, &tmp_fbo); - } - - wb.release(); - - data.resize(data_size); - - Image *img = memnew(Image(texture->alloc_width, texture->alloc_height, false, Image::FORMAT_RGBA8, data)); - if (!texture->compressed) { - img->convert(real_format); - } - - return Ref<Image>(img); - } - -#ifdef GLES_OVER_GL - - Image::Format real_format; - GLenum gl_format; - GLenum gl_internal_format; - GLenum gl_type; - bool compressed; - bool srgb; - _get_gl_image_and_format(Ref<Image>(), texture->format, texture->flags, real_format, gl_format, gl_internal_format, gl_type, compressed, srgb, false); - - PoolVector<uint8_t> data; - - int data_size = Image::get_image_data_size(texture->alloc_width, texture->alloc_height, real_format, texture->mipmaps > 1); - - data.resize(data_size * 2); //add some memory at the end, just in case for buggy drivers - PoolVector<uint8_t>::Write wb = data.write(); - - glActiveTexture(GL_TEXTURE0); - - glBindTexture(texture->target, texture->tex_id); - - glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); - - for (int i = 0; i < texture->mipmaps; i++) { - - int ofs = Image::get_image_mipmap_offset(texture->alloc_width, texture->alloc_height, real_format, i); - - if (texture->compressed) { - - glPixelStorei(GL_PACK_ALIGNMENT, 4); - glGetCompressedTexImage(texture->target, i, &wb[ofs]); - - } else { - - glPixelStorei(GL_PACK_ALIGNMENT, 1); - - glGetTexImage(texture->target, i, texture->gl_format_cache, texture->gl_type_cache, &wb[ofs]); - } - } - - Image::Format img_format; - - //convert special case RGB10_A2 to RGBA8 because it's not a supported image format - if (texture->gl_internal_format_cache == GL_RGB10_A2) { - - img_format = Image::FORMAT_RGBA8; - - uint32_t *ptr = (uint32_t *)wb.ptr(); - uint32_t num_pixels = data_size / 4; - - for (uint32_t ofs = 0; ofs < num_pixels; ofs++) { - uint32_t px = ptr[ofs]; - uint32_t a = px >> 30 & 0xFF; - - ptr[ofs] = (px >> 2 & 0xFF) | - (px >> 12 & 0xFF) << 8 | - (px >> 22 & 0xFF) << 16 | - (a | a << 2 | a << 4 | a << 6) << 24; - } - } else { - img_format = real_format; - } - - wb.release(); - - data.resize(data_size); - - Image *img = memnew(Image(texture->alloc_width, texture->alloc_height, texture->mipmaps > 1, img_format, data)); - - return Ref<Image>(img); -#else - - Image::Format real_format; - GLenum gl_format; - GLenum gl_internal_format; - GLenum gl_type; - bool compressed; - bool srgb; - _get_gl_image_and_format(Ref<Image>(), texture->format, texture->flags, real_format, gl_format, gl_internal_format, gl_type, compressed, srgb, texture->is_npot_repeat_mipmap); - - PoolVector<uint8_t> data; - - int data_size = Image::get_image_data_size(texture->alloc_width, texture->alloc_height, Image::FORMAT_RGBA8, false); - - data.resize(data_size * 2); //add some memory at the end, just in case for buggy drivers - PoolVector<uint8_t>::Write wb = data.write(); - - GLuint temp_framebuffer; - glGenFramebuffers(1, &temp_framebuffer); - - GLuint temp_color_texture; - glGenTextures(1, &temp_color_texture); - - glBindFramebuffer(GL_FRAMEBUFFER, temp_framebuffer); - - glBindTexture(GL_TEXTURE_2D, temp_color_texture); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture->alloc_width, texture->alloc_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, temp_color_texture, 0); - - glDepthMask(GL_FALSE); - glDisable(GL_DEPTH_TEST); - glDisable(GL_CULL_FACE); - glDisable(GL_BLEND); - glDepthFunc(GL_LEQUAL); - glColorMask(1, 1, 1, 1); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, texture->tex_id); - - glViewport(0, 0, texture->alloc_width, texture->alloc_height); - - shaders.copy.set_conditional(CopyShaderGLES3::LINEAR_TO_SRGB, !srgb); - shaders.copy.bind(); - - glClearColor(0.0, 0.0, 0.0, 0.0); - glClear(GL_COLOR_BUFFER_BIT); - glBindVertexArray(resources.quadie_array); - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - glBindVertexArray(0); - - glReadPixels(0, 0, texture->alloc_width, texture->alloc_height, GL_RGBA, GL_UNSIGNED_BYTE, &wb[0]); - - shaders.copy.set_conditional(CopyShaderGLES3::LINEAR_TO_SRGB, false); - - glDeleteTextures(1, &temp_color_texture); - - glBindFramebuffer(GL_FRAMEBUFFER, 0); - glDeleteFramebuffers(1, &temp_framebuffer); - - wb.release(); - - data.resize(data_size); - - Image *img = memnew(Image(texture->alloc_width, texture->alloc_height, false, Image::FORMAT_RGBA8, data)); - if (!texture->compressed) { - img->convert(real_format); - } - - return Ref<Image>(img); -#endif -} - -void RasterizerStorageGLES3::texture_set_flags(RID p_texture, uint32_t p_flags) { - - Texture *texture = texture_owner.get(p_texture); - ERR_FAIL_COND(!texture); - if (texture->render_target) { - - p_flags &= VS::TEXTURE_FLAG_FILTER; //can change only filter - } - - bool had_mipmaps = texture->flags & VS::TEXTURE_FLAG_MIPMAPS; - - texture->flags = p_flags; - - glActiveTexture(GL_TEXTURE0); - glBindTexture(texture->target, texture->tex_id); - - if (((texture->flags & VS::TEXTURE_FLAG_REPEAT) || (texture->flags & VS::TEXTURE_FLAG_MIRRORED_REPEAT)) && texture->target != GL_TEXTURE_CUBE_MAP) { - - if (texture->flags & VS::TEXTURE_FLAG_MIRRORED_REPEAT) { - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT); - } else { - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - } - } else { - //glTexParameterf( texture->target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE ); - glTexParameterf(texture->target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameterf(texture->target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - } - - if (config.use_anisotropic_filter) { - - if (texture->flags & VS::TEXTURE_FLAG_ANISOTROPIC_FILTER) { - - glTexParameterf(texture->target, _GL_TEXTURE_MAX_ANISOTROPY_EXT, config.anisotropic_level); - } else { - glTexParameterf(texture->target, _GL_TEXTURE_MAX_ANISOTROPY_EXT, 1); - } - } - - if ((texture->flags & VS::TEXTURE_FLAG_MIPMAPS) && !texture->ignore_mipmaps) { - if (!had_mipmaps && texture->mipmaps == 1) { - glGenerateMipmap(texture->target); - } - glTexParameteri(texture->target, GL_TEXTURE_MIN_FILTER, config.use_fast_texture_filter ? GL_LINEAR_MIPMAP_NEAREST : GL_LINEAR_MIPMAP_LINEAR); - - } else { - if (texture->flags & VS::TEXTURE_FLAG_FILTER) { - glTexParameteri(texture->target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - } else { - glTexParameteri(texture->target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - } - } - - if (config.srgb_decode_supported && texture->srgb) { - - if (texture->flags & VS::TEXTURE_FLAG_CONVERT_TO_LINEAR) { - - glTexParameteri(texture->target, _TEXTURE_SRGB_DECODE_EXT, _DECODE_EXT); - texture->using_srgb = true; - } else { - glTexParameteri(texture->target, _TEXTURE_SRGB_DECODE_EXT, _SKIP_DECODE_EXT); - texture->using_srgb = false; - } - } - - if (texture->flags & VS::TEXTURE_FLAG_FILTER) { - - glTexParameteri(texture->target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // Linear Filtering - - } else { - - glTexParameteri(texture->target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); // raw Filtering - } -} -uint32_t RasterizerStorageGLES3::texture_get_flags(RID p_texture) const { - - Texture *texture = texture_owner.get(p_texture); - - ERR_FAIL_COND_V(!texture, 0); - - return texture->flags; -} -Image::Format RasterizerStorageGLES3::texture_get_format(RID p_texture) const { - - Texture *texture = texture_owner.get(p_texture); - - ERR_FAIL_COND_V(!texture, Image::FORMAT_L8); - - return texture->format; -} - -VisualServer::TextureType RasterizerStorageGLES3::texture_get_type(RID p_texture) const { - Texture *texture = texture_owner.get(p_texture); - - ERR_FAIL_COND_V(!texture, VS::TEXTURE_TYPE_2D); - - return texture->type; -} -uint32_t RasterizerStorageGLES3::texture_get_texid(RID p_texture) const { - - Texture *texture = texture_owner.get(p_texture); - - ERR_FAIL_COND_V(!texture, 0); - - return texture->tex_id; -} -void RasterizerStorageGLES3::texture_bind(RID p_texture, uint32_t p_texture_no) { - - Texture *texture = texture_owner.getornull(p_texture); - - ERR_FAIL_COND(!texture); - - glActiveTexture(GL_TEXTURE0 + p_texture_no); - glBindTexture(texture->target, texture->tex_id); -} -uint32_t RasterizerStorageGLES3::texture_get_width(RID p_texture) const { - - Texture *texture = texture_owner.get(p_texture); - - ERR_FAIL_COND_V(!texture, 0); - - return texture->width; -} -uint32_t RasterizerStorageGLES3::texture_get_height(RID p_texture) const { - - Texture *texture = texture_owner.get(p_texture); - - ERR_FAIL_COND_V(!texture, 0); - - return texture->height; -} - -uint32_t RasterizerStorageGLES3::texture_get_depth(RID p_texture) const { - - Texture *texture = texture_owner.get(p_texture); - - ERR_FAIL_COND_V(!texture, 0); - - return texture->depth; -} - -void RasterizerStorageGLES3::texture_set_size_override(RID p_texture, int p_width, int p_height, int p_depth) { - - Texture *texture = texture_owner.get(p_texture); - - ERR_FAIL_COND(!texture); - ERR_FAIL_COND(texture->render_target); - - ERR_FAIL_COND(p_width <= 0 || p_width > 16384); - ERR_FAIL_COND(p_height <= 0 || p_height > 16384); - //real texture size is in alloc width and height - texture->width = p_width; - texture->height = p_height; -} - -void RasterizerStorageGLES3::texture_set_path(RID p_texture, const String &p_path) { - Texture *texture = texture_owner.get(p_texture); - ERR_FAIL_COND(!texture); - - texture->path = p_path; -} - -String RasterizerStorageGLES3::texture_get_path(RID p_texture) const { - - Texture *texture = texture_owner.get(p_texture); - ERR_FAIL_COND_V(!texture, String()); - return texture->path; -} -void RasterizerStorageGLES3::texture_debug_usage(List<VS::TextureInfo> *r_info) { - - List<RID> textures; - texture_owner.get_owned_list(&textures); - - for (List<RID>::Element *E = textures.front(); E; E = E->next()) { - - Texture *t = texture_owner.get(E->get()); - if (!t) - continue; - VS::TextureInfo tinfo; - tinfo.path = t->path; - tinfo.format = t->format; - tinfo.width = t->alloc_width; - tinfo.height = t->alloc_height; - tinfo.depth = t->alloc_depth; - tinfo.bytes = t->total_data_size; - r_info->push_back(tinfo); - } -} - -void RasterizerStorageGLES3::texture_set_shrink_all_x2_on_set_data(bool p_enable) { - - config.shrink_textures_x2 = p_enable; -} - -void RasterizerStorageGLES3::textures_keep_original(bool p_enable) { - - config.keep_original_textures = p_enable; -} - -void RasterizerStorageGLES3::texture_set_detect_3d_callback(RID p_texture, VisualServer::TextureDetectCallback p_callback, void *p_userdata) { - - Texture *texture = texture_owner.get(p_texture); - ERR_FAIL_COND(!texture); - - texture->detect_3d = p_callback; - texture->detect_3d_ud = p_userdata; -} - -void RasterizerStorageGLES3::texture_set_detect_srgb_callback(RID p_texture, VisualServer::TextureDetectCallback p_callback, void *p_userdata) { - Texture *texture = texture_owner.get(p_texture); - ERR_FAIL_COND(!texture); - - texture->detect_srgb = p_callback; - texture->detect_srgb_ud = p_userdata; -} - -void RasterizerStorageGLES3::texture_set_detect_normal_callback(RID p_texture, VisualServer::TextureDetectCallback p_callback, void *p_userdata) { - Texture *texture = texture_owner.get(p_texture); - ERR_FAIL_COND(!texture); - - texture->detect_normal = p_callback; - texture->detect_normal_ud = p_userdata; -} - -RID RasterizerStorageGLES3::texture_create_radiance_cubemap(RID p_source, int p_resolution) const { - - Texture *texture = texture_owner.get(p_source); - ERR_FAIL_COND_V(!texture, RID()); - ERR_FAIL_COND_V(texture->type != VS::TEXTURE_TYPE_CUBEMAP, RID()); - - bool use_float = config.framebuffer_half_float_supported; - - if (p_resolution < 0) { - p_resolution = texture->width; - } - - glBindVertexArray(0); - glDisable(GL_CULL_FACE); - glDisable(GL_DEPTH_TEST); - glDisable(GL_SCISSOR_TEST); - glDisable(GL_BLEND); - - glActiveTexture(GL_TEXTURE0); - glBindTexture(texture->target, texture->tex_id); - - if (config.srgb_decode_supported && texture->srgb && !texture->using_srgb) { - - glTexParameteri(texture->target, _TEXTURE_SRGB_DECODE_EXT, _DECODE_EXT); - texture->using_srgb = true; -#ifdef TOOLS_ENABLED - if (!(texture->flags & VS::TEXTURE_FLAG_CONVERT_TO_LINEAR)) { - texture->flags |= VS::TEXTURE_FLAG_CONVERT_TO_LINEAR; - //notify that texture must be set to linear beforehand, so it works in other platforms when exported - } -#endif - } - - glActiveTexture(GL_TEXTURE1); - GLuint new_cubemap; - glGenTextures(1, &new_cubemap); - glBindTexture(GL_TEXTURE_CUBE_MAP, new_cubemap); - - GLuint tmp_fb; - - glGenFramebuffers(1, &tmp_fb); - glBindFramebuffer(GL_FRAMEBUFFER, tmp_fb); - - int size = p_resolution; - - int lod = 0; - - shaders.cubemap_filter.bind(); - - int mipmaps = 6; - - int mm_level = mipmaps; - - GLenum internal_format = use_float ? GL_RGBA16F : GL_RGB10_A2; - GLenum format = GL_RGBA; - GLenum type = use_float ? GL_HALF_FLOAT : GL_UNSIGNED_INT_2_10_10_10_REV; - - while (mm_level) { - - for (int i = 0; i < 6; i++) { - glTexImage2D(_cube_side_enum[i], lod, internal_format, size, size, 0, format, type, NULL); - } - - lod++; - mm_level--; - - if (size > 1) - size >>= 1; - } - - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_BASE_LEVEL, 0); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAX_LEVEL, lod - 1); - - lod = 0; - mm_level = mipmaps; - - size = p_resolution; - - shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::USE_DUAL_PARABOLOID, false); - - while (mm_level) { - - for (int i = 0; i < 6; i++) { - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, _cube_side_enum[i], new_cubemap, lod); - - glViewport(0, 0, size, size); - glBindVertexArray(resources.quadie_array); - - shaders.cubemap_filter.set_uniform(CubemapFilterShaderGLES3::FACE_ID, i); - shaders.cubemap_filter.set_uniform(CubemapFilterShaderGLES3::ROUGHNESS, lod / float(mipmaps - 1)); - - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - glBindVertexArray(0); -#ifdef DEBUG_ENABLED - GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); - ERR_CONTINUE(status != GL_FRAMEBUFFER_COMPLETE); -#endif - } - - if (size > 1) - size >>= 1; - lod++; - mm_level--; - } - - //restore ranges - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_BASE_LEVEL, 0); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAX_LEVEL, lod - 1); - - glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); - - glBindFramebuffer(GL_FRAMEBUFFER, RasterizerStorageGLES3::system_fbo); - glDeleteFramebuffers(1, &tmp_fb); - - Texture *ctex = memnew(Texture); - - ctex->type = VS::TEXTURE_TYPE_CUBEMAP; - ctex->flags = VS::TEXTURE_FLAG_MIPMAPS | VS::TEXTURE_FLAG_FILTER; - ctex->width = p_resolution; - ctex->height = p_resolution; - ctex->alloc_width = p_resolution; - ctex->alloc_height = p_resolution; - ctex->format = use_float ? Image::FORMAT_RGBAH : Image::FORMAT_RGBA8; - ctex->target = GL_TEXTURE_CUBE_MAP; - ctex->gl_format_cache = format; - ctex->gl_internal_format_cache = internal_format; - ctex->gl_type_cache = type; - ctex->data_size = 0; - ctex->compressed = false; - ctex->srgb = false; - ctex->total_data_size = 0; - ctex->ignore_mipmaps = false; - ctex->mipmaps = mipmaps; - ctex->active = true; - ctex->tex_id = new_cubemap; - ctex->stored_cube_sides = (1 << 6) - 1; - ctex->render_target = NULL; - - return texture_owner.make_rid(ctex); -} - -Size2 RasterizerStorageGLES3::texture_size_with_proxy(RID p_texture) const { - - const Texture *texture = texture_owner.getornull(p_texture); - ERR_FAIL_COND_V(!texture, Size2()); - if (texture->proxy) { - return Size2(texture->proxy->width, texture->proxy->height); - } else { - return Size2(texture->width, texture->height); - } -} - -void RasterizerStorageGLES3::texture_set_proxy(RID p_texture, RID p_proxy) { - - Texture *texture = texture_owner.get(p_texture); - ERR_FAIL_COND(!texture); - - if (texture->proxy) { - texture->proxy->proxy_owners.erase(texture); - texture->proxy = NULL; - } - - if (p_proxy.is_valid()) { - Texture *proxy = texture_owner.get(p_proxy); - ERR_FAIL_COND(!proxy); - ERR_FAIL_COND(proxy == texture); - proxy->proxy_owners.insert(texture); - texture->proxy = proxy; - } -} - -void RasterizerStorageGLES3::texture_set_force_redraw_if_visible(RID p_texture, bool p_enable) { - - Texture *texture = texture_owner.get(p_texture); - ERR_FAIL_COND(!texture); - texture->redraw_if_visible = p_enable; -} - -RID RasterizerStorageGLES3::sky_create() { - - Sky *sky = memnew(Sky); - sky->radiance = 0; - sky->irradiance = 0; - return sky_owner.make_rid(sky); -} - -void RasterizerStorageGLES3::sky_set_texture(RID p_sky, RID p_panorama, int p_radiance_size) { - - Sky *sky = sky_owner.getornull(p_sky); - ERR_FAIL_COND(!sky); - - if (sky->panorama.is_valid()) { - sky->panorama = RID(); - glDeleteTextures(1, &sky->radiance); - glDeleteTextures(1, &sky->irradiance); - sky->radiance = 0; - sky->irradiance = 0; - } - - sky->panorama = p_panorama; - if (!sky->panorama.is_valid()) - return; //cleared - - Texture *texture = texture_owner.getornull(sky->panorama); - if (!texture) { - sky->panorama = RID(); - ERR_FAIL_COND(!texture); - } - - texture = texture->get_ptr(); //resolve for proxies - - glBindVertexArray(0); - glDisable(GL_CULL_FACE); - glDisable(GL_DEPTH_TEST); - glDisable(GL_SCISSOR_TEST); - glDisable(GL_BLEND); - - glActiveTexture(GL_TEXTURE0); - glBindTexture(texture->target, texture->tex_id); - glTexParameteri(texture->target, GL_TEXTURE_BASE_LEVEL, 0); -#ifdef GLES_OVER_GL - glTexParameteri(texture->target, GL_TEXTURE_MAX_LEVEL, int(Math::floor(Math::log(float(texture->width)) / Math::log(2.0f)))); - glGenerateMipmap(texture->target); -#else - glTexParameteri(texture->target, GL_TEXTURE_MAX_LEVEL, 0); -#endif - // Need Mipmaps regardless of whether they are set in import by user - glTexParameterf(texture->target, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameterf(texture->target, GL_TEXTURE_WRAP_T, GL_REPEAT); -#ifdef GLES_OVER_GL - glTexParameterf(texture->target, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); -#else - glTexParameterf(texture->target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); -#endif - glTexParameterf(texture->target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - - if (config.srgb_decode_supported && texture->srgb && !texture->using_srgb) { - - glTexParameteri(texture->target, _TEXTURE_SRGB_DECODE_EXT, _DECODE_EXT); - texture->using_srgb = true; -#ifdef TOOLS_ENABLED - if (!(texture->flags & VS::TEXTURE_FLAG_CONVERT_TO_LINEAR)) { - texture->flags |= VS::TEXTURE_FLAG_CONVERT_TO_LINEAR; - //notify that texture must be set to linear beforehand, so it works in other platforms when exported - } -#endif - } - - { - //Irradiance map - glActiveTexture(GL_TEXTURE1); - glGenTextures(1, &sky->irradiance); - glBindTexture(GL_TEXTURE_2D, sky->irradiance); - - GLuint tmp_fb; - - glGenFramebuffers(1, &tmp_fb); - glBindFramebuffer(GL_FRAMEBUFFER, tmp_fb); - - int size = 32; - - bool use_float = config.framebuffer_half_float_supported; - - GLenum internal_format = use_float ? GL_RGBA16F : GL_RGB10_A2; - GLenum format = GL_RGBA; - GLenum type = use_float ? GL_HALF_FLOAT : GL_UNSIGNED_INT_2_10_10_10_REV; - - glTexImage2D(GL_TEXTURE_2D, 0, internal_format, size, size * 2, 0, format, type, NULL); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); - glTexParameterf(texture->target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameterf(texture->target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, sky->irradiance, 0); - - int irradiance_size = GLOBAL_GET("rendering/quality/reflections/irradiance_max_size"); - int upscale_size = MIN(int(previous_power_of_2(irradiance_size)), p_radiance_size); - - GLuint tmp_fb2; - GLuint tmp_tex; - { - //generate another one for rendering, as can't read and write from a single texarray it seems - glGenFramebuffers(1, &tmp_fb2); - glBindFramebuffer(GL_FRAMEBUFFER, tmp_fb2); - glGenTextures(1, &tmp_tex); - glBindTexture(GL_TEXTURE_2D, tmp_tex); - glTexImage2D(GL_TEXTURE_2D, 0, internal_format, upscale_size, 2.0 * upscale_size, 0, format, type, NULL); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tmp_tex, 0); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); -#ifdef DEBUG_ENABLED - GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); - ERR_FAIL_COND(status != GL_FRAMEBUFFER_COMPLETE); -#endif - } - - shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::USE_DUAL_PARABOLOID, true); - shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::USE_SOURCE_PANORAMA, true); - shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::COMPUTE_IRRADIANCE, true); - shaders.cubemap_filter.bind(); - - // Very large Panoramas require way too much effort to compute irradiance so use a mipmap - // level that corresponds to a panorama of 1024x512 - shaders.cubemap_filter.set_uniform(CubemapFilterShaderGLES3::SOURCE_MIP_LEVEL, MAX(Math::floor(Math::log(float(texture->width)) / Math::log(2.0f)) - 10.0f, 0.0f)); - - // Compute Irradiance for a large texture, specified by radiance size and then pull out a low mipmap corresponding to 32x32 - for (int i = 0; i < 2; i++) { - glViewport(0, i * upscale_size, upscale_size, upscale_size); - glBindVertexArray(resources.quadie_array); - - shaders.cubemap_filter.set_uniform(CubemapFilterShaderGLES3::Z_FLIP, i > 0); - - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - glBindVertexArray(0); - } - glGenerateMipmap(GL_TEXTURE_2D); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, tmp_tex); - glBindFramebuffer(GL_FRAMEBUFFER, tmp_fb); - - shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::USE_DUAL_PARABOLOID, false); - shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::USE_SOURCE_PANORAMA, false); - shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::COMPUTE_IRRADIANCE, false); - - shaders.copy.set_conditional(CopyShaderGLES3::USE_LOD, true); - shaders.copy.bind(); - shaders.copy.set_uniform(CopyShaderGLES3::MIP_LEVEL, MAX(Math::floor(Math::log(float(upscale_size)) / Math::log(2.0f)) - 5.0f, 0.0f)); // Mip level that corresponds to a 32x32 texture - - glViewport(0, 0, size, size * 2.0); - glBindVertexArray(resources.quadie_array); - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - glBindVertexArray(0); - - shaders.copy.set_conditional(CopyShaderGLES3::USE_LOD, false); - - glBindFramebuffer(GL_FRAMEBUFFER, RasterizerStorageGLES3::system_fbo); - glActiveTexture(GL_TEXTURE0); - glBindTexture(texture->target, texture->tex_id); - glDeleteFramebuffers(1, &tmp_fb); - glDeleteFramebuffers(1, &tmp_fb2); - glDeleteTextures(1, &tmp_tex); - } - - // Now compute radiance - - glActiveTexture(GL_TEXTURE1); - glGenTextures(1, &sky->radiance); - - if (config.use_texture_array_environment) { - - //texture3D - glBindTexture(GL_TEXTURE_2D_ARRAY, sky->radiance); - - GLuint tmp_fb; - - glGenFramebuffers(1, &tmp_fb); - glBindFramebuffer(GL_FRAMEBUFFER, tmp_fb); - - int size = p_radiance_size; - - int array_level = 6; - - bool use_float = config.framebuffer_half_float_supported; - - GLenum internal_format = use_float ? GL_RGBA16F : GL_RGB10_A2; - GLenum format = GL_RGBA; - GLenum type = use_float ? GL_HALF_FLOAT : GL_UNSIGNED_INT_2_10_10_10_REV; - - glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, internal_format, size, size * 2, array_level, 0, format, type, NULL); - - glTexParameterf(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameterf(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - - GLuint tmp_fb2; - GLuint tmp_tex; - { - //generate another one for rendering, as can't read and write from a single texarray it seems - glGenFramebuffers(1, &tmp_fb2); - glBindFramebuffer(GL_FRAMEBUFFER, tmp_fb2); - glGenTextures(1, &tmp_tex); - glBindTexture(GL_TEXTURE_2D, tmp_tex); - glTexImage2D(GL_TEXTURE_2D, 0, internal_format, size, size * 2, 0, format, type, NULL); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tmp_tex, 0); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); -#ifdef DEBUG_ENABLED - GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); - ERR_FAIL_COND(status != GL_FRAMEBUFFER_COMPLETE); -#endif - } - - for (int j = 0; j < array_level; j++) { - - glBindFramebuffer(GL_FRAMEBUFFER, tmp_fb2); - -#ifdef GLES_OVER_GL - if (j < 3) { -#else - if (j == 0) { -#endif - - shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::USE_DUAL_PARABOLOID, true); - shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::USE_SOURCE_PANORAMA, true); - shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::USE_SOURCE_DUAL_PARABOLOID_ARRAY, false); - shaders.cubemap_filter.bind(); - glActiveTexture(GL_TEXTURE0); - glBindTexture(texture->target, texture->tex_id); - shaders.cubemap_filter.set_uniform(CubemapFilterShaderGLES3::SOURCE_RESOLUTION, float(texture->width / 4)); - } else { - - shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::USE_DUAL_PARABOLOID, true); - shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::USE_SOURCE_PANORAMA, false); - shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::USE_SOURCE_DUAL_PARABOLOID_ARRAY, true); - shaders.cubemap_filter.bind(); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D_ARRAY, sky->radiance); - shaders.cubemap_filter.set_uniform(CubemapFilterShaderGLES3::SOURCE_ARRAY_INDEX, j - 1); //read from previous to ensure better blur - } - - for (int i = 0; i < 2; i++) { - glViewport(0, i * size, size, size); - glBindVertexArray(resources.quadie_array); - - shaders.cubemap_filter.set_uniform(CubemapFilterShaderGLES3::Z_FLIP, i > 0); - shaders.cubemap_filter.set_uniform(CubemapFilterShaderGLES3::ROUGHNESS, j / float(array_level - 1)); - - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - glBindVertexArray(0); - } - - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, tmp_fb); - glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, sky->radiance, 0, j); - glBindFramebuffer(GL_READ_FRAMEBUFFER, tmp_fb2); - glReadBuffer(GL_COLOR_ATTACHMENT0); - glBlitFramebuffer(0, 0, size, size * 2, 0, 0, size, size * 2, GL_COLOR_BUFFER_BIT, GL_NEAREST); - glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); - } - - shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::USE_SOURCE_PANORAMA, false); - shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::USE_DUAL_PARABOLOID, false); - shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::USE_SOURCE_DUAL_PARABOLOID_ARRAY, false); - - //restore ranges - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D_ARRAY, sky->radiance); - - glGenerateMipmap(GL_TEXTURE_2D_ARRAY); - - glTexParameterf(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - glTexParameterf(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameterf(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameterf(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - glBindFramebuffer(GL_FRAMEBUFFER, RasterizerStorageGLES3::system_fbo); - glDeleteFramebuffers(1, &tmp_fb); - glDeleteFramebuffers(1, &tmp_fb2); - glDeleteTextures(1, &tmp_tex); - - } else { - //regular single texture with mipmaps - glBindTexture(GL_TEXTURE_2D, sky->radiance); - - GLuint tmp_fb; - - glGenFramebuffers(1, &tmp_fb); - glBindFramebuffer(GL_FRAMEBUFFER, tmp_fb); - - int size = p_radiance_size; - - int lod = 0; - - int mipmaps = 6; - - int mm_level = mipmaps; - - bool use_float = config.framebuffer_half_float_supported; - - GLenum internal_format = use_float ? GL_RGBA16F : GL_RGB10_A2; - GLenum format = GL_RGBA; - GLenum type = use_float ? GL_HALF_FLOAT : GL_UNSIGNED_INT_2_10_10_10_REV; - - glTexStorage2DCustom(GL_TEXTURE_2D, mipmaps, internal_format, size, size * 2.0, format, type); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, mipmaps - 1); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - - GLuint tmp_fb2; - GLuint tmp_tex; - { - // Need a temporary framebuffer for rendering so we can read from previous iterations - glGenFramebuffers(1, &tmp_fb2); - glBindFramebuffer(GL_FRAMEBUFFER, tmp_fb2); - glGenTextures(1, &tmp_tex); - glBindTexture(GL_TEXTURE_2D, tmp_tex); - glTexImage2D(GL_TEXTURE_2D, 0, internal_format, size, size * 2, 0, format, type, NULL); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tmp_tex, 0); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); -#ifdef DEBUG_ENABLED - GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); - ERR_FAIL_COND(status != GL_FRAMEBUFFER_COMPLETE); -#endif - } - - lod = 0; - mm_level = mipmaps; - - size = p_radiance_size; - - while (mm_level) { - glBindFramebuffer(GL_FRAMEBUFFER, tmp_fb); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, sky->radiance, lod); - -#ifdef DEBUG_ENABLED - GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); - ERR_CONTINUE(status != GL_FRAMEBUFFER_COMPLETE); -#endif - glBindTexture(GL_TEXTURE_2D, tmp_tex); - glTexImage2D(GL_TEXTURE_2D, 0, internal_format, size, size * 2, 0, format, type, NULL); - glBindFramebuffer(GL_FRAMEBUFFER, tmp_fb2); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tmp_tex, 0); -#ifdef GLES_OVER_GL - if (lod < 3) { -#else - if (lod == 0) { -#endif - - shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::USE_DUAL_PARABOLOID, true); - shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::USE_SOURCE_PANORAMA, true); - shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::USE_SOURCE_DUAL_PARABOLOID, false); - shaders.cubemap_filter.bind(); - glActiveTexture(GL_TEXTURE0); - glBindTexture(texture->target, texture->tex_id); - shaders.cubemap_filter.set_uniform(CubemapFilterShaderGLES3::SOURCE_RESOLUTION, float(texture->width / 4)); - } else { - - shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::USE_DUAL_PARABOLOID, true); - shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::USE_SOURCE_PANORAMA, false); - shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::USE_SOURCE_DUAL_PARABOLOID, true); - shaders.cubemap_filter.bind(); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, sky->radiance); - shaders.cubemap_filter.set_uniform(CubemapFilterShaderGLES3::SOURCE_MIP_LEVEL, float(lod - 1)); //read from previous to ensure better blur - } - - for (int i = 0; i < 2; i++) { - glViewport(0, i * size, size, size); - glBindVertexArray(resources.quadie_array); - - shaders.cubemap_filter.set_uniform(CubemapFilterShaderGLES3::Z_FLIP, i > 0); - shaders.cubemap_filter.set_uniform(CubemapFilterShaderGLES3::ROUGHNESS, lod / float(mipmaps - 1)); - - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - glBindVertexArray(0); - } - - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, tmp_fb); - glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, sky->radiance, 0, lod); - glBindFramebuffer(GL_READ_FRAMEBUFFER, tmp_fb2); - glReadBuffer(GL_COLOR_ATTACHMENT0); - glBlitFramebuffer(0, 0, size, size * 2, 0, 0, size, size * 2, GL_COLOR_BUFFER_BIT, GL_NEAREST); - glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); - - if (size > 1) - size >>= 1; - lod++; - mm_level--; - } - shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::USE_DUAL_PARABOLOID, false); - shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::USE_SOURCE_PANORAMA, false); - - //restore ranges - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, lod - 1); - - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - glBindFramebuffer(GL_FRAMEBUFFER, RasterizerStorageGLES3::system_fbo); - glDeleteFramebuffers(1, &tmp_fb); - glDeleteFramebuffers(1, &tmp_fb2); - glDeleteTextures(1, &tmp_tex); - } -} - -/* SHADER API */ - -RID RasterizerStorageGLES3::shader_create() { - - Shader *shader = memnew(Shader); - shader->mode = VS::SHADER_SPATIAL; - shader->shader = &scene->state.scene_shader; - RID rid = shader_owner.make_rid(shader); - _shader_make_dirty(shader); - shader->self = rid; - - return rid; -} - -void RasterizerStorageGLES3::_shader_make_dirty(Shader *p_shader) { - - if (p_shader->dirty_list.in_list()) - return; - - _shader_dirty_list.add(&p_shader->dirty_list); -} - -void RasterizerStorageGLES3::shader_set_code(RID p_shader, const String &p_code) { - - Shader *shader = shader_owner.get(p_shader); - ERR_FAIL_COND(!shader); - - shader->code = p_code; - - String mode_string = ShaderLanguage::get_shader_type(p_code); - VS::ShaderMode mode; - - if (mode_string == "canvas_item") - mode = VS::SHADER_CANVAS_ITEM; - else if (mode_string == "particles") - mode = VS::SHADER_PARTICLES; - else - mode = VS::SHADER_SPATIAL; - - if (shader->custom_code_id && mode != shader->mode) { - - shader->shader->free_custom_shader(shader->custom_code_id); - shader->custom_code_id = 0; - } - - shader->mode = mode; - - ShaderGLES3 *shaders[VS::SHADER_MAX] = { - &scene->state.scene_shader, - &canvas->state.canvas_shader, - &this->shaders.particles, - - }; - - shader->shader = shaders[mode]; - - if (shader->custom_code_id == 0) { - shader->custom_code_id = shader->shader->create_custom_shader(); - } - - _shader_make_dirty(shader); -} -String RasterizerStorageGLES3::shader_get_code(RID p_shader) const { - - const Shader *shader = shader_owner.get(p_shader); - ERR_FAIL_COND_V(!shader, String()); - - return shader->code; -} - -void RasterizerStorageGLES3::_update_shader(Shader *p_shader) const { - - _shader_dirty_list.remove(&p_shader->dirty_list); - - p_shader->valid = false; - p_shader->ubo_size = 0; - - p_shader->uniforms.clear(); - - if (p_shader->code == String()) { - return; //just invalid, but no error - } - - ShaderCompilerGLES3::GeneratedCode gen_code; - ShaderCompilerGLES3::IdentifierActions *actions = NULL; - - switch (p_shader->mode) { - case VS::SHADER_CANVAS_ITEM: { - - p_shader->canvas_item.light_mode = Shader::CanvasItem::LIGHT_MODE_NORMAL; - p_shader->canvas_item.blend_mode = Shader::CanvasItem::BLEND_MODE_MIX; - p_shader->canvas_item.uses_screen_texture = false; - p_shader->canvas_item.uses_screen_uv = false; - p_shader->canvas_item.uses_time = false; - - shaders.actions_canvas.render_mode_values["blend_add"] = Pair<int *, int>(&p_shader->canvas_item.blend_mode, Shader::CanvasItem::BLEND_MODE_ADD); - shaders.actions_canvas.render_mode_values["blend_mix"] = Pair<int *, int>(&p_shader->canvas_item.blend_mode, Shader::CanvasItem::BLEND_MODE_MIX); - shaders.actions_canvas.render_mode_values["blend_sub"] = Pair<int *, int>(&p_shader->canvas_item.blend_mode, Shader::CanvasItem::BLEND_MODE_SUB); - shaders.actions_canvas.render_mode_values["blend_mul"] = Pair<int *, int>(&p_shader->canvas_item.blend_mode, Shader::CanvasItem::BLEND_MODE_MUL); - shaders.actions_canvas.render_mode_values["blend_premul_alpha"] = Pair<int *, int>(&p_shader->canvas_item.blend_mode, Shader::CanvasItem::BLEND_MODE_PMALPHA); - shaders.actions_canvas.render_mode_values["blend_disabled"] = Pair<int *, int>(&p_shader->canvas_item.blend_mode, Shader::CanvasItem::BLEND_MODE_DISABLED); - - shaders.actions_canvas.render_mode_values["unshaded"] = Pair<int *, int>(&p_shader->canvas_item.light_mode, Shader::CanvasItem::LIGHT_MODE_UNSHADED); - shaders.actions_canvas.render_mode_values["light_only"] = Pair<int *, int>(&p_shader->canvas_item.light_mode, Shader::CanvasItem::LIGHT_MODE_LIGHT_ONLY); - - shaders.actions_canvas.usage_flag_pointers["SCREEN_UV"] = &p_shader->canvas_item.uses_screen_uv; - shaders.actions_canvas.usage_flag_pointers["SCREEN_PIXEL_SIZE"] = &p_shader->canvas_item.uses_screen_uv; - shaders.actions_canvas.usage_flag_pointers["SCREEN_TEXTURE"] = &p_shader->canvas_item.uses_screen_texture; - shaders.actions_canvas.usage_flag_pointers["TIME"] = &p_shader->canvas_item.uses_time; - - actions = &shaders.actions_canvas; - actions->uniforms = &p_shader->uniforms; - - } break; - - case VS::SHADER_SPATIAL: { - - p_shader->spatial.blend_mode = Shader::Spatial::BLEND_MODE_MIX; - p_shader->spatial.depth_draw_mode = Shader::Spatial::DEPTH_DRAW_OPAQUE; - p_shader->spatial.cull_mode = Shader::Spatial::CULL_MODE_BACK; - p_shader->spatial.uses_alpha = false; - p_shader->spatial.uses_alpha_scissor = false; - p_shader->spatial.uses_discard = false; - p_shader->spatial.unshaded = false; - p_shader->spatial.no_depth_test = false; - p_shader->spatial.uses_sss = false; - p_shader->spatial.uses_time = false; - p_shader->spatial.uses_vertex_lighting = false; - p_shader->spatial.uses_screen_texture = false; - p_shader->spatial.uses_depth_texture = false; - p_shader->spatial.uses_vertex = false; - p_shader->spatial.writes_modelview_or_projection = false; - p_shader->spatial.uses_world_coordinates = false; - - shaders.actions_scene.render_mode_values["blend_add"] = Pair<int *, int>(&p_shader->spatial.blend_mode, Shader::Spatial::BLEND_MODE_ADD); - shaders.actions_scene.render_mode_values["blend_mix"] = Pair<int *, int>(&p_shader->spatial.blend_mode, Shader::Spatial::BLEND_MODE_MIX); - shaders.actions_scene.render_mode_values["blend_sub"] = Pair<int *, int>(&p_shader->spatial.blend_mode, Shader::Spatial::BLEND_MODE_SUB); - shaders.actions_scene.render_mode_values["blend_mul"] = Pair<int *, int>(&p_shader->spatial.blend_mode, Shader::Spatial::BLEND_MODE_MUL); - - shaders.actions_scene.render_mode_values["depth_draw_opaque"] = Pair<int *, int>(&p_shader->spatial.depth_draw_mode, Shader::Spatial::DEPTH_DRAW_OPAQUE); - shaders.actions_scene.render_mode_values["depth_draw_always"] = Pair<int *, int>(&p_shader->spatial.depth_draw_mode, Shader::Spatial::DEPTH_DRAW_ALWAYS); - shaders.actions_scene.render_mode_values["depth_draw_never"] = Pair<int *, int>(&p_shader->spatial.depth_draw_mode, Shader::Spatial::DEPTH_DRAW_NEVER); - shaders.actions_scene.render_mode_values["depth_draw_alpha_prepass"] = Pair<int *, int>(&p_shader->spatial.depth_draw_mode, Shader::Spatial::DEPTH_DRAW_ALPHA_PREPASS); - - shaders.actions_scene.render_mode_values["cull_front"] = Pair<int *, int>(&p_shader->spatial.cull_mode, Shader::Spatial::CULL_MODE_FRONT); - shaders.actions_scene.render_mode_values["cull_back"] = Pair<int *, int>(&p_shader->spatial.cull_mode, Shader::Spatial::CULL_MODE_BACK); - shaders.actions_scene.render_mode_values["cull_disabled"] = Pair<int *, int>(&p_shader->spatial.cull_mode, Shader::Spatial::CULL_MODE_DISABLED); - - shaders.actions_scene.render_mode_flags["unshaded"] = &p_shader->spatial.unshaded; - shaders.actions_scene.render_mode_flags["depth_test_disable"] = &p_shader->spatial.no_depth_test; - - shaders.actions_scene.render_mode_flags["vertex_lighting"] = &p_shader->spatial.uses_vertex_lighting; - - shaders.actions_scene.render_mode_flags["world_vertex_coords"] = &p_shader->spatial.uses_world_coordinates; - - shaders.actions_scene.usage_flag_pointers["ALPHA"] = &p_shader->spatial.uses_alpha; - shaders.actions_scene.usage_flag_pointers["ALPHA_SCISSOR"] = &p_shader->spatial.uses_alpha_scissor; - - shaders.actions_scene.usage_flag_pointers["SSS_STRENGTH"] = &p_shader->spatial.uses_sss; - shaders.actions_scene.usage_flag_pointers["DISCARD"] = &p_shader->spatial.uses_discard; - shaders.actions_scene.usage_flag_pointers["SCREEN_TEXTURE"] = &p_shader->spatial.uses_screen_texture; - shaders.actions_scene.usage_flag_pointers["DEPTH_TEXTURE"] = &p_shader->spatial.uses_depth_texture; - shaders.actions_scene.usage_flag_pointers["TIME"] = &p_shader->spatial.uses_time; - - shaders.actions_scene.write_flag_pointers["MODELVIEW_MATRIX"] = &p_shader->spatial.writes_modelview_or_projection; - shaders.actions_scene.write_flag_pointers["PROJECTION_MATRIX"] = &p_shader->spatial.writes_modelview_or_projection; - shaders.actions_scene.write_flag_pointers["VERTEX"] = &p_shader->spatial.uses_vertex; - - actions = &shaders.actions_scene; - actions->uniforms = &p_shader->uniforms; - - } break; - case VS::SHADER_PARTICLES: { - - actions = &shaders.actions_particles; - actions->uniforms = &p_shader->uniforms; - } break; - case VS::SHADER_MAX: - break; // Can't happen, but silences warning - } - - Error err = shaders.compiler.compile(p_shader->mode, p_shader->code, actions, p_shader->path, gen_code); - if (err != OK) { - return; - } - - p_shader->shader->set_custom_shader_code(p_shader->custom_code_id, gen_code.vertex, gen_code.vertex_global, gen_code.fragment, gen_code.light, gen_code.fragment_global, gen_code.uniforms, gen_code.texture_uniforms, gen_code.defines); - - p_shader->ubo_size = gen_code.uniform_total_size; - p_shader->ubo_offsets = gen_code.uniform_offsets; - p_shader->texture_count = gen_code.texture_uniforms.size(); - p_shader->texture_hints = gen_code.texture_hints; - p_shader->texture_types = gen_code.texture_types; - - p_shader->uses_vertex_time = gen_code.uses_vertex_time; - p_shader->uses_fragment_time = gen_code.uses_fragment_time; - - //all materials using this shader will have to be invalidated, unfortunately - - for (SelfList<Material> *E = p_shader->materials.first(); E; E = E->next()) { - - _material_make_dirty(E->self()); - } - - p_shader->valid = true; - p_shader->version++; -} - -void RasterizerStorageGLES3::update_dirty_shaders() { - - while (_shader_dirty_list.first()) { - _update_shader(_shader_dirty_list.first()->self()); - } -} - -void RasterizerStorageGLES3::shader_get_param_list(RID p_shader, List<PropertyInfo> *p_param_list) const { - - Shader *shader = shader_owner.get(p_shader); - ERR_FAIL_COND(!shader); - - if (shader->dirty_list.in_list()) - _update_shader(shader); // ok should be not anymore dirty - - Map<int, StringName> order; - - for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = shader->uniforms.front(); E; E = E->next()) { - - if (E->get().texture_order >= 0) { - order[E->get().texture_order + 100000] = E->key(); - } else { - order[E->get().order] = E->key(); - } - } - - for (Map<int, StringName>::Element *E = order.front(); E; E = E->next()) { - - PropertyInfo pi; - ShaderLanguage::ShaderNode::Uniform &u = shader->uniforms[E->get()]; - pi.name = E->get(); - switch (u.type) { - case ShaderLanguage::TYPE_VOID: pi.type = Variant::NIL; break; - case ShaderLanguage::TYPE_BOOL: pi.type = Variant::BOOL; break; - case ShaderLanguage::TYPE_BVEC2: - pi.type = Variant::INT; - pi.hint = PROPERTY_HINT_FLAGS; - pi.hint_string = "x,y"; - break; - case ShaderLanguage::TYPE_BVEC3: - pi.type = Variant::INT; - pi.hint = PROPERTY_HINT_FLAGS; - pi.hint_string = "x,y,z"; - break; - case ShaderLanguage::TYPE_BVEC4: - pi.type = Variant::INT; - pi.hint = PROPERTY_HINT_FLAGS; - pi.hint_string = "x,y,z,w"; - break; - case ShaderLanguage::TYPE_UINT: - case ShaderLanguage::TYPE_INT: { - pi.type = Variant::INT; - if (u.hint == ShaderLanguage::ShaderNode::Uniform::HINT_RANGE) { - pi.hint = PROPERTY_HINT_RANGE; - pi.hint_string = rtos(u.hint_range[0]) + "," + rtos(u.hint_range[1]) + "," + rtos(u.hint_range[2]); - } - - } break; - case ShaderLanguage::TYPE_IVEC2: - case ShaderLanguage::TYPE_IVEC3: - case ShaderLanguage::TYPE_IVEC4: - case ShaderLanguage::TYPE_UVEC2: - case ShaderLanguage::TYPE_UVEC3: - case ShaderLanguage::TYPE_UVEC4: { - - pi.type = Variant::POOL_INT_ARRAY; - } break; - case ShaderLanguage::TYPE_FLOAT: { - pi.type = Variant::REAL; - if (u.hint == ShaderLanguage::ShaderNode::Uniform::HINT_RANGE) { - pi.hint = PROPERTY_HINT_RANGE; - pi.hint_string = rtos(u.hint_range[0]) + "," + rtos(u.hint_range[1]) + "," + rtos(u.hint_range[2]); - } - - } break; - case ShaderLanguage::TYPE_VEC2: pi.type = Variant::VECTOR2; break; - case ShaderLanguage::TYPE_VEC3: pi.type = Variant::VECTOR3; break; - case ShaderLanguage::TYPE_VEC4: { - if (u.hint == ShaderLanguage::ShaderNode::Uniform::HINT_COLOR) { - pi.type = Variant::COLOR; - } else { - pi.type = Variant::PLANE; - } - } break; - case ShaderLanguage::TYPE_MAT2: pi.type = Variant::TRANSFORM2D; break; - case ShaderLanguage::TYPE_MAT3: pi.type = Variant::BASIS; break; - case ShaderLanguage::TYPE_MAT4: pi.type = Variant::TRANSFORM; break; - case ShaderLanguage::TYPE_SAMPLER2D: - case ShaderLanguage::TYPE_ISAMPLER2D: - case ShaderLanguage::TYPE_USAMPLER2D: { - - pi.type = Variant::OBJECT; - pi.hint = PROPERTY_HINT_RESOURCE_TYPE; - pi.hint_string = "Texture"; - } break; - case ShaderLanguage::TYPE_SAMPLER2DARRAY: - case ShaderLanguage::TYPE_ISAMPLER2DARRAY: - case ShaderLanguage::TYPE_USAMPLER2DARRAY: { - - pi.type = Variant::OBJECT; - pi.hint = PROPERTY_HINT_RESOURCE_TYPE; - pi.hint_string = "TextureArray"; - } break; - case ShaderLanguage::TYPE_SAMPLER3D: - case ShaderLanguage::TYPE_ISAMPLER3D: - case ShaderLanguage::TYPE_USAMPLER3D: { - pi.type = Variant::OBJECT; - pi.hint = PROPERTY_HINT_RESOURCE_TYPE; - pi.hint_string = "Texture3D"; - } break; - case ShaderLanguage::TYPE_SAMPLERCUBE: { - - pi.type = Variant::OBJECT; - pi.hint = PROPERTY_HINT_RESOURCE_TYPE; - pi.hint_string = "CubeMap"; - } break; - }; - - p_param_list->push_back(pi); - } -} - -void RasterizerStorageGLES3::shader_set_default_texture_param(RID p_shader, const StringName &p_name, RID p_texture) { - - Shader *shader = shader_owner.get(p_shader); - ERR_FAIL_COND(!shader); - ERR_FAIL_COND(p_texture.is_valid() && !texture_owner.owns(p_texture)); - - if (p_texture.is_valid()) - shader->default_textures[p_name] = p_texture; - else - shader->default_textures.erase(p_name); - - _shader_make_dirty(shader); -} -RID RasterizerStorageGLES3::shader_get_default_texture_param(RID p_shader, const StringName &p_name) const { - - const Shader *shader = shader_owner.get(p_shader); - ERR_FAIL_COND_V(!shader, RID()); - - const Map<StringName, RID>::Element *E = shader->default_textures.find(p_name); - if (!E) - return RID(); - return E->get(); -} - -/* COMMON MATERIAL API */ - -void RasterizerStorageGLES3::_material_make_dirty(Material *p_material) const { - - if (p_material->dirty_list.in_list()) - return; - - _material_dirty_list.add(&p_material->dirty_list); -} - -RID RasterizerStorageGLES3::material_create() { - - Material *material = memnew(Material); - - return material_owner.make_rid(material); -} - -void RasterizerStorageGLES3::material_set_shader(RID p_material, RID p_shader) { - - Material *material = material_owner.get(p_material); - ERR_FAIL_COND(!material); - - Shader *shader = shader_owner.getornull(p_shader); - - if (material->shader) { - //if shader, remove from previous shader material list - material->shader->materials.remove(&material->list); - } - material->shader = shader; - - if (shader) { - shader->materials.add(&material->list); - } - - _material_make_dirty(material); -} - -RID RasterizerStorageGLES3::material_get_shader(RID p_material) const { - - const Material *material = material_owner.get(p_material); - ERR_FAIL_COND_V(!material, RID()); - - if (material->shader) - return material->shader->self; - - return RID(); -} - -void RasterizerStorageGLES3::material_set_param(RID p_material, const StringName &p_param, const Variant &p_value) { - - Material *material = material_owner.get(p_material); - ERR_FAIL_COND(!material); - - if (p_value.get_type() == Variant::NIL) - material->params.erase(p_param); - else - material->params[p_param] = p_value; - - _material_make_dirty(material); -} -Variant RasterizerStorageGLES3::material_get_param(RID p_material, const StringName &p_param) const { - - const Material *material = material_owner.get(p_material); - ERR_FAIL_COND_V(!material, Variant()); - - if (material->params.has(p_param)) - return material->params[p_param]; - - return material_get_param_default(p_material, p_param); -} - -Variant RasterizerStorageGLES3::material_get_param_default(RID p_material, const StringName &p_param) const { - const Material *material = material_owner.get(p_material); - ERR_FAIL_COND_V(!material, Variant()); - - if (material->shader) { - if (material->shader->uniforms.has(p_param)) { - ShaderLanguage::ShaderNode::Uniform uniform = material->shader->uniforms[p_param]; - Vector<ShaderLanguage::ConstantNode::Value> default_value = uniform.default_value; - return ShaderLanguage::constant_value_to_variant(default_value, uniform.type, uniform.hint); - } - } - return Variant(); -} - -void RasterizerStorageGLES3::material_set_line_width(RID p_material, float p_width) { - - Material *material = material_owner.get(p_material); - ERR_FAIL_COND(!material); - - material->line_width = p_width; -} - -void RasterizerStorageGLES3::material_set_next_pass(RID p_material, RID p_next_material) { - - Material *material = material_owner.get(p_material); - ERR_FAIL_COND(!material); - - material->next_pass = p_next_material; -} - -bool RasterizerStorageGLES3::material_is_animated(RID p_material) { - - Material *material = material_owner.get(p_material); - ERR_FAIL_COND_V(!material, false); - if (material->dirty_list.in_list()) { - _update_material(material); - } - - bool animated = material->is_animated_cache; - if (!animated && material->next_pass.is_valid()) { - animated = material_is_animated(material->next_pass); - } - return animated; -} -bool RasterizerStorageGLES3::material_casts_shadows(RID p_material) { - - Material *material = material_owner.get(p_material); - ERR_FAIL_COND_V(!material, false); - if (material->dirty_list.in_list()) { - _update_material(material); - } - - bool casts_shadows = material->can_cast_shadow_cache; - - if (!casts_shadows && material->next_pass.is_valid()) { - casts_shadows = material_casts_shadows(material->next_pass); - } - - return casts_shadows; -} - -void RasterizerStorageGLES3::material_add_instance_owner(RID p_material, RasterizerScene::InstanceBase *p_instance) { - - Material *material = material_owner.get(p_material); - ERR_FAIL_COND(!material); - - Map<RasterizerScene::InstanceBase *, int>::Element *E = material->instance_owners.find(p_instance); - if (E) { - E->get()++; - } else { - material->instance_owners[p_instance] = 1; - } -} - -void RasterizerStorageGLES3::material_remove_instance_owner(RID p_material, RasterizerScene::InstanceBase *p_instance) { - - Material *material = material_owner.get(p_material); - ERR_FAIL_COND(!material); - - Map<RasterizerScene::InstanceBase *, int>::Element *E = material->instance_owners.find(p_instance); - ERR_FAIL_COND(!E); - E->get()--; - - if (E->get() == 0) { - material->instance_owners.erase(E); - } -} - -void RasterizerStorageGLES3::material_set_render_priority(RID p_material, int priority) { - - ERR_FAIL_COND(priority < VS::MATERIAL_RENDER_PRIORITY_MIN); - ERR_FAIL_COND(priority > VS::MATERIAL_RENDER_PRIORITY_MAX); - - Material *material = material_owner.get(p_material); - ERR_FAIL_COND(!material); - - material->render_priority = priority; -} - -_FORCE_INLINE_ static void _fill_std140_variant_ubo_value(ShaderLanguage::DataType type, const Variant &value, uint8_t *data, bool p_linear_color) { - switch (type) { - case ShaderLanguage::TYPE_BOOL: { - - bool v = value; - - GLuint *gui = (GLuint *)data; - *gui = v ? GL_TRUE : GL_FALSE; - } break; - case ShaderLanguage::TYPE_BVEC2: { - - int v = value; - GLuint *gui = (GLuint *)data; - gui[0] = (v & 1) ? GL_TRUE : GL_FALSE; - gui[1] = (v & 2) ? GL_TRUE : GL_FALSE; - - } break; - case ShaderLanguage::TYPE_BVEC3: { - - int v = value; - GLuint *gui = (GLuint *)data; - gui[0] = (v & 1) ? GL_TRUE : GL_FALSE; - gui[1] = (v & 2) ? GL_TRUE : GL_FALSE; - gui[2] = (v & 4) ? GL_TRUE : GL_FALSE; - - } break; - case ShaderLanguage::TYPE_BVEC4: { - - int v = value; - GLuint *gui = (GLuint *)data; - gui[0] = (v & 1) ? GL_TRUE : GL_FALSE; - gui[1] = (v & 2) ? GL_TRUE : GL_FALSE; - gui[2] = (v & 4) ? GL_TRUE : GL_FALSE; - gui[3] = (v & 8) ? GL_TRUE : GL_FALSE; - - } break; - case ShaderLanguage::TYPE_INT: { - - int v = value; - GLint *gui = (GLint *)data; - gui[0] = v; - - } break; - case ShaderLanguage::TYPE_IVEC2: { - - PoolVector<int> iv = value; - int s = iv.size(); - GLint *gui = (GLint *)data; - - PoolVector<int>::Read r = iv.read(); - - for (int i = 0; i < 2; i++) { - if (i < s) - gui[i] = r[i]; - else - gui[i] = 0; - } - - } break; - case ShaderLanguage::TYPE_IVEC3: { - - PoolVector<int> iv = value; - int s = iv.size(); - GLint *gui = (GLint *)data; - - PoolVector<int>::Read r = iv.read(); - - for (int i = 0; i < 3; i++) { - if (i < s) - gui[i] = r[i]; - else - gui[i] = 0; - } - } break; - case ShaderLanguage::TYPE_IVEC4: { - - PoolVector<int> iv = value; - int s = iv.size(); - GLint *gui = (GLint *)data; - - PoolVector<int>::Read r = iv.read(); - - for (int i = 0; i < 4; i++) { - if (i < s) - gui[i] = r[i]; - else - gui[i] = 0; - } - } break; - case ShaderLanguage::TYPE_UINT: { - - int v = value; - GLuint *gui = (GLuint *)data; - gui[0] = v; - - } break; - case ShaderLanguage::TYPE_UVEC2: { - - PoolVector<int> iv = value; - int s = iv.size(); - GLuint *gui = (GLuint *)data; - - PoolVector<int>::Read r = iv.read(); - - for (int i = 0; i < 2; i++) { - if (i < s) - gui[i] = r[i]; - else - gui[i] = 0; - } - } break; - case ShaderLanguage::TYPE_UVEC3: { - PoolVector<int> iv = value; - int s = iv.size(); - GLuint *gui = (GLuint *)data; - - PoolVector<int>::Read r = iv.read(); - - for (int i = 0; i < 3; i++) { - if (i < s) - gui[i] = r[i]; - else - gui[i] = 0; - } - - } break; - case ShaderLanguage::TYPE_UVEC4: { - PoolVector<int> iv = value; - int s = iv.size(); - GLuint *gui = (GLuint *)data; - - PoolVector<int>::Read r = iv.read(); - - for (int i = 0; i < 4; i++) { - if (i < s) - gui[i] = r[i]; - else - gui[i] = 0; - } - } break; - case ShaderLanguage::TYPE_FLOAT: { - float v = value; - GLfloat *gui = (GLfloat *)data; - gui[0] = v; - - } break; - case ShaderLanguage::TYPE_VEC2: { - Vector2 v = value; - GLfloat *gui = (GLfloat *)data; - gui[0] = v.x; - gui[1] = v.y; - - } break; - case ShaderLanguage::TYPE_VEC3: { - Vector3 v = value; - GLfloat *gui = (GLfloat *)data; - gui[0] = v.x; - gui[1] = v.y; - gui[2] = v.z; - - } break; - case ShaderLanguage::TYPE_VEC4: { - - GLfloat *gui = (GLfloat *)data; - - if (value.get_type() == Variant::COLOR) { - Color v = value; - - if (p_linear_color) { - v = v.to_linear(); - } - - gui[0] = v.r; - gui[1] = v.g; - gui[2] = v.b; - gui[3] = v.a; - } else if (value.get_type() == Variant::RECT2) { - Rect2 v = value; - - gui[0] = v.position.x; - gui[1] = v.position.y; - gui[2] = v.size.x; - gui[3] = v.size.y; - } else if (value.get_type() == Variant::QUAT) { - Quat v = value; - - gui[0] = v.x; - gui[1] = v.y; - gui[2] = v.z; - gui[3] = v.w; - } else { - Plane v = value; - - gui[0] = v.normal.x; - gui[1] = v.normal.y; - gui[2] = v.normal.z; - gui[3] = v.d; - } - } break; - case ShaderLanguage::TYPE_MAT2: { - Transform2D v = value; - GLfloat *gui = (GLfloat *)data; - - //in std140 members of mat2 are treated as vec4s - gui[0] = v.elements[0][0]; - gui[1] = v.elements[0][1]; - gui[2] = 0; - gui[3] = 0; - gui[4] = v.elements[1][0]; - gui[5] = v.elements[1][1]; - gui[6] = 0; - gui[7] = 0; - } break; - case ShaderLanguage::TYPE_MAT3: { - - Basis v = value; - GLfloat *gui = (GLfloat *)data; - - gui[0] = v.elements[0][0]; - gui[1] = v.elements[1][0]; - gui[2] = v.elements[2][0]; - gui[3] = 0; - gui[4] = v.elements[0][1]; - gui[5] = v.elements[1][1]; - gui[6] = v.elements[2][1]; - gui[7] = 0; - gui[8] = v.elements[0][2]; - gui[9] = v.elements[1][2]; - gui[10] = v.elements[2][2]; - gui[11] = 0; - } break; - case ShaderLanguage::TYPE_MAT4: { - - Transform v = value; - GLfloat *gui = (GLfloat *)data; - - gui[0] = v.basis.elements[0][0]; - gui[1] = v.basis.elements[1][0]; - gui[2] = v.basis.elements[2][0]; - gui[3] = 0; - gui[4] = v.basis.elements[0][1]; - gui[5] = v.basis.elements[1][1]; - gui[6] = v.basis.elements[2][1]; - gui[7] = 0; - gui[8] = v.basis.elements[0][2]; - gui[9] = v.basis.elements[1][2]; - gui[10] = v.basis.elements[2][2]; - gui[11] = 0; - gui[12] = v.origin.x; - gui[13] = v.origin.y; - gui[14] = v.origin.z; - gui[15] = 1; - } break; - default: { - } - } -} - -_FORCE_INLINE_ static void _fill_std140_ubo_value(ShaderLanguage::DataType type, const Vector<ShaderLanguage::ConstantNode::Value> &value, uint8_t *data) { - - switch (type) { - case ShaderLanguage::TYPE_BOOL: { - - GLuint *gui = (GLuint *)data; - *gui = value[0].boolean ? GL_TRUE : GL_FALSE; - } break; - case ShaderLanguage::TYPE_BVEC2: { - - GLuint *gui = (GLuint *)data; - gui[0] = value[0].boolean ? GL_TRUE : GL_FALSE; - gui[1] = value[1].boolean ? GL_TRUE : GL_FALSE; - - } break; - case ShaderLanguage::TYPE_BVEC3: { - - GLuint *gui = (GLuint *)data; - gui[0] = value[0].boolean ? GL_TRUE : GL_FALSE; - gui[1] = value[1].boolean ? GL_TRUE : GL_FALSE; - gui[2] = value[2].boolean ? GL_TRUE : GL_FALSE; - - } break; - case ShaderLanguage::TYPE_BVEC4: { - - GLuint *gui = (GLuint *)data; - gui[0] = value[0].boolean ? GL_TRUE : GL_FALSE; - gui[1] = value[1].boolean ? GL_TRUE : GL_FALSE; - gui[2] = value[2].boolean ? GL_TRUE : GL_FALSE; - gui[3] = value[3].boolean ? GL_TRUE : GL_FALSE; - - } break; - case ShaderLanguage::TYPE_INT: { - - GLint *gui = (GLint *)data; - gui[0] = value[0].sint; - - } break; - case ShaderLanguage::TYPE_IVEC2: { - - GLint *gui = (GLint *)data; - - for (int i = 0; i < 2; i++) { - gui[i] = value[i].sint; - } - - } break; - case ShaderLanguage::TYPE_IVEC3: { - - GLint *gui = (GLint *)data; - - for (int i = 0; i < 3; i++) { - gui[i] = value[i].sint; - } - - } break; - case ShaderLanguage::TYPE_IVEC4: { - - GLint *gui = (GLint *)data; - - for (int i = 0; i < 4; i++) { - gui[i] = value[i].sint; - } - - } break; - case ShaderLanguage::TYPE_UINT: { - - GLuint *gui = (GLuint *)data; - gui[0] = value[0].uint; - - } break; - case ShaderLanguage::TYPE_UVEC2: { - - GLint *gui = (GLint *)data; - - for (int i = 0; i < 2; i++) { - gui[i] = value[i].uint; - } - } break; - case ShaderLanguage::TYPE_UVEC3: { - GLint *gui = (GLint *)data; - - for (int i = 0; i < 3; i++) { - gui[i] = value[i].uint; - } - - } break; - case ShaderLanguage::TYPE_UVEC4: { - GLint *gui = (GLint *)data; - - for (int i = 0; i < 4; i++) { - gui[i] = value[i].uint; - } - } break; - case ShaderLanguage::TYPE_FLOAT: { - - GLfloat *gui = (GLfloat *)data; - gui[0] = value[0].real; - - } break; - case ShaderLanguage::TYPE_VEC2: { - - GLfloat *gui = (GLfloat *)data; - - for (int i = 0; i < 2; i++) { - gui[i] = value[i].real; - } - - } break; - case ShaderLanguage::TYPE_VEC3: { - - GLfloat *gui = (GLfloat *)data; - - for (int i = 0; i < 3; i++) { - gui[i] = value[i].real; - } - - } break; - case ShaderLanguage::TYPE_VEC4: { - - GLfloat *gui = (GLfloat *)data; - - for (int i = 0; i < 4; i++) { - gui[i] = value[i].real; - } - } break; - case ShaderLanguage::TYPE_MAT2: { - GLfloat *gui = (GLfloat *)data; - - //in std140 members of mat2 are treated as vec4s - gui[0] = value[0].real; - gui[1] = value[1].real; - gui[2] = 0; - gui[3] = 0; - gui[4] = value[2].real; - gui[5] = value[3].real; - gui[6] = 0; - gui[7] = 0; - } break; - case ShaderLanguage::TYPE_MAT3: { - - GLfloat *gui = (GLfloat *)data; - - gui[0] = value[0].real; - gui[1] = value[1].real; - gui[2] = value[2].real; - gui[3] = 0; - gui[4] = value[3].real; - gui[5] = value[4].real; - gui[6] = value[5].real; - gui[7] = 0; - gui[8] = value[6].real; - gui[9] = value[7].real; - gui[10] = value[8].real; - gui[11] = 0; - } break; - case ShaderLanguage::TYPE_MAT4: { - - GLfloat *gui = (GLfloat *)data; - - for (int i = 0; i < 16; i++) { - gui[i] = value[i].real; - } - } break; - default: { - } - } -} - -_FORCE_INLINE_ static void _fill_std140_ubo_empty(ShaderLanguage::DataType type, uint8_t *data) { - - switch (type) { - - case ShaderLanguage::TYPE_BOOL: - case ShaderLanguage::TYPE_INT: - case ShaderLanguage::TYPE_UINT: - case ShaderLanguage::TYPE_FLOAT: { - zeromem(data, 4); - } break; - case ShaderLanguage::TYPE_BVEC2: - case ShaderLanguage::TYPE_IVEC2: - case ShaderLanguage::TYPE_UVEC2: - case ShaderLanguage::TYPE_VEC2: { - zeromem(data, 8); - } break; - case ShaderLanguage::TYPE_BVEC3: - case ShaderLanguage::TYPE_IVEC3: - case ShaderLanguage::TYPE_UVEC3: - case ShaderLanguage::TYPE_VEC3: { - zeromem(data, 12); - } break; - case ShaderLanguage::TYPE_BVEC4: - case ShaderLanguage::TYPE_IVEC4: - case ShaderLanguage::TYPE_UVEC4: - case ShaderLanguage::TYPE_VEC4: { - - zeromem(data, 16); - } break; - case ShaderLanguage::TYPE_MAT2: { - - zeromem(data, 32); - } break; - case ShaderLanguage::TYPE_MAT3: { - - zeromem(data, 48); - } break; - case ShaderLanguage::TYPE_MAT4: { - zeromem(data, 64); - } break; - - default: { - } - } -} - -void RasterizerStorageGLES3::_update_material(Material *material) { - - if (material->dirty_list.in_list()) - _material_dirty_list.remove(&material->dirty_list); - - if (material->shader && material->shader->dirty_list.in_list()) { - _update_shader(material->shader); - } - - if (material->shader && !material->shader->valid) - return; - - //update caches - - { - bool can_cast_shadow = false; - bool is_animated = false; - - if (material->shader && material->shader->mode == VS::SHADER_SPATIAL) { - - if (material->shader->spatial.blend_mode == Shader::Spatial::BLEND_MODE_MIX && - (!material->shader->spatial.uses_alpha || material->shader->spatial.depth_draw_mode == Shader::Spatial::DEPTH_DRAW_ALPHA_PREPASS)) { - can_cast_shadow = true; - } - - if (material->shader->spatial.uses_discard && material->shader->uses_fragment_time) { - is_animated = true; - } - - if (material->shader->spatial.uses_vertex && material->shader->uses_vertex_time) { - is_animated = true; - } - - if (can_cast_shadow != material->can_cast_shadow_cache || is_animated != material->is_animated_cache) { - material->can_cast_shadow_cache = can_cast_shadow; - material->is_animated_cache = is_animated; - - for (Map<Geometry *, int>::Element *E = material->geometry_owners.front(); E; E = E->next()) { - E->key()->material_changed_notify(); - } - - for (Map<RasterizerScene::InstanceBase *, int>::Element *E = material->instance_owners.front(); E; E = E->next()) { - E->key()->base_changed(false, true); - } - } - } - } - - //clear ubo if it needs to be cleared - if (material->ubo_size) { - - if (!material->shader || material->shader->ubo_size != material->ubo_size) { - //by by ubo - glDeleteBuffers(1, &material->ubo_id); - material->ubo_id = 0; - material->ubo_size = 0; - } - } - - //create ubo if it needs to be created - if (material->ubo_size == 0 && material->shader && material->shader->ubo_size) { - - glGenBuffers(1, &material->ubo_id); - glBindBuffer(GL_UNIFORM_BUFFER, material->ubo_id); - glBufferData(GL_UNIFORM_BUFFER, material->shader->ubo_size, NULL, GL_STATIC_DRAW); - glBindBuffer(GL_UNIFORM_BUFFER, 0); - material->ubo_size = material->shader->ubo_size; - } - - //fill up the UBO if it needs to be filled - if (material->shader && material->ubo_size) { - uint8_t *local_ubo = (uint8_t *)alloca(material->ubo_size); - - for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = material->shader->uniforms.front(); E; E = E->next()) { - - if (E->get().order < 0) - continue; // texture, does not go here - - //regular uniform - uint8_t *data = &local_ubo[material->shader->ubo_offsets[E->get().order]]; - - Map<StringName, Variant>::Element *V = material->params.find(E->key()); - - if (V) { - //user provided - _fill_std140_variant_ubo_value(E->get().type, V->get(), data, material->shader->mode == VS::SHADER_SPATIAL); - - } else if (E->get().default_value.size()) { - //default value - _fill_std140_ubo_value(E->get().type, E->get().default_value, data); - //value=E->get().default_value; - } else { - //zero because it was not provided - if (E->get().type == ShaderLanguage::TYPE_VEC4 && E->get().hint == ShaderLanguage::ShaderNode::Uniform::HINT_COLOR) { - //colors must be set as black, with alpha as 1.0 - _fill_std140_variant_ubo_value(E->get().type, Color(0, 0, 0, 1), data, material->shader->mode == VS::SHADER_SPATIAL); - } else { - //else just zero it out - _fill_std140_ubo_empty(E->get().type, data); - } - } - } - - glBindBuffer(GL_UNIFORM_BUFFER, material->ubo_id); - glBufferData(GL_UNIFORM_BUFFER, material->ubo_size, local_ubo, GL_STATIC_DRAW); - glBindBuffer(GL_UNIFORM_BUFFER, 0); - } - - //set up the texture array, for easy access when it needs to be drawn - if (material->shader && material->shader->texture_count) { - - material->texture_is_3d.resize(material->shader->texture_count); - material->textures.resize(material->shader->texture_count); - - for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = material->shader->uniforms.front(); E; E = E->next()) { - - if (E->get().texture_order < 0) - continue; // not a texture, does not go here - - RID texture; - - switch (E->get().type) { - case ShaderLanguage::TYPE_SAMPLER3D: - case ShaderLanguage::TYPE_SAMPLER2DARRAY: { - material->texture_is_3d.write[E->get().texture_order] = true; - } break; - default: { - material->texture_is_3d.write[E->get().texture_order] = false; - } break; - } - - Map<StringName, Variant>::Element *V = material->params.find(E->key()); - if (V) { - texture = V->get(); - } - - if (!texture.is_valid()) { - Map<StringName, RID>::Element *W = material->shader->default_textures.find(E->key()); - if (W) { - texture = W->get(); - } - } - - material->textures.write[E->get().texture_order] = texture; - } - - } else { - material->textures.clear(); - material->texture_is_3d.clear(); - } -} - -void RasterizerStorageGLES3::_material_add_geometry(RID p_material, Geometry *p_geometry) { - - Material *material = material_owner.getornull(p_material); - ERR_FAIL_COND(!material); - - Map<Geometry *, int>::Element *I = material->geometry_owners.find(p_geometry); - - if (I) { - I->get()++; - } else { - material->geometry_owners[p_geometry] = 1; - } -} - -void RasterizerStorageGLES3::_material_remove_geometry(RID p_material, Geometry *p_geometry) { - - Material *material = material_owner.getornull(p_material); - ERR_FAIL_COND(!material); - - Map<Geometry *, int>::Element *I = material->geometry_owners.find(p_geometry); - ERR_FAIL_COND(!I); - - I->get()--; - if (I->get() == 0) { - material->geometry_owners.erase(I); - } -} - -void RasterizerStorageGLES3::update_dirty_materials() { - - while (_material_dirty_list.first()) { - - Material *material = _material_dirty_list.first()->self(); - - _update_material(material); - } -} - -/* MESH API */ - -RID RasterizerStorageGLES3::mesh_create() { - - Mesh *mesh = memnew(Mesh); - - return mesh_owner.make_rid(mesh); -} - -void RasterizerStorageGLES3::mesh_add_surface(RID p_mesh, uint32_t p_format, VS::PrimitiveType p_primitive, const PoolVector<uint8_t> &p_array, int p_vertex_count, const PoolVector<uint8_t> &p_index_array, int p_index_count, const AABB &p_aabb, const Vector<PoolVector<uint8_t> > &p_blend_shapes, const Vector<AABB> &p_bone_aabbs) { - - PoolVector<uint8_t> array = p_array; - - Mesh *mesh = mesh_owner.getornull(p_mesh); - ERR_FAIL_COND(!mesh); - - ERR_FAIL_COND(!(p_format & VS::ARRAY_FORMAT_VERTEX)); - - //must have index and bones, both. - { - uint32_t bones_weight = VS::ARRAY_FORMAT_BONES | VS::ARRAY_FORMAT_WEIGHTS; - ERR_FAIL_COND_MSG((p_format & bones_weight) && (p_format & bones_weight) != bones_weight, "Array must have both bones and weights in format or none."); - } - - //bool has_morph = p_blend_shapes.size(); - - Surface::Attrib attribs[VS::ARRAY_MAX]; - - int stride = 0; - - for (int i = 0; i < VS::ARRAY_MAX; i++) { - - attribs[i].index = i; - - if (!(p_format & (1 << i))) { - attribs[i].enabled = false; - attribs[i].integer = false; - continue; - } - - attribs[i].enabled = true; - attribs[i].offset = stride; - attribs[i].integer = false; - - switch (i) { - - case VS::ARRAY_VERTEX: { - - if (p_format & VS::ARRAY_FLAG_USE_2D_VERTICES) { - attribs[i].size = 2; - } else { - attribs[i].size = (p_format & VS::ARRAY_COMPRESS_VERTEX) ? 4 : 3; - } - - if (p_format & VS::ARRAY_COMPRESS_VERTEX) { - attribs[i].type = GL_HALF_FLOAT; - stride += attribs[i].size * 2; - } else { - attribs[i].type = GL_FLOAT; - stride += attribs[i].size * 4; - } - - attribs[i].normalized = GL_FALSE; - - } break; - case VS::ARRAY_NORMAL: { - - attribs[i].size = 3; - - if (p_format & VS::ARRAY_COMPRESS_NORMAL) { - attribs[i].type = GL_BYTE; - stride += 4; //pad extra byte - attribs[i].normalized = GL_TRUE; - } else { - attribs[i].type = GL_FLOAT; - stride += 12; - attribs[i].normalized = GL_FALSE; - } - - } break; - case VS::ARRAY_TANGENT: { - - attribs[i].size = 4; - - if (p_format & VS::ARRAY_COMPRESS_TANGENT) { - attribs[i].type = GL_BYTE; - stride += 4; - attribs[i].normalized = GL_TRUE; - } else { - attribs[i].type = GL_FLOAT; - stride += 16; - attribs[i].normalized = GL_FALSE; - } - - } break; - case VS::ARRAY_COLOR: { - - attribs[i].size = 4; - - if (p_format & VS::ARRAY_COMPRESS_COLOR) { - attribs[i].type = GL_UNSIGNED_BYTE; - stride += 4; - attribs[i].normalized = GL_TRUE; - } else { - attribs[i].type = GL_FLOAT; - stride += 16; - attribs[i].normalized = GL_FALSE; - } - - } break; - case VS::ARRAY_TEX_UV: { - - attribs[i].size = 2; - - if (p_format & VS::ARRAY_COMPRESS_TEX_UV) { - attribs[i].type = GL_HALF_FLOAT; - stride += 4; - } else { - attribs[i].type = GL_FLOAT; - stride += 8; - } - - attribs[i].normalized = GL_FALSE; - - } break; - case VS::ARRAY_TEX_UV2: { - - attribs[i].size = 2; - - if (p_format & VS::ARRAY_COMPRESS_TEX_UV2) { - attribs[i].type = GL_HALF_FLOAT; - stride += 4; - } else { - attribs[i].type = GL_FLOAT; - stride += 8; - } - attribs[i].normalized = GL_FALSE; - - } break; - case VS::ARRAY_BONES: { - - attribs[i].size = 4; - - if (p_format & VS::ARRAY_FLAG_USE_16_BIT_BONES) { - attribs[i].type = GL_UNSIGNED_SHORT; - stride += 8; - } else { - attribs[i].type = GL_UNSIGNED_BYTE; - stride += 4; - } - - attribs[i].normalized = GL_FALSE; - attribs[i].integer = true; - - } break; - case VS::ARRAY_WEIGHTS: { - - attribs[i].size = 4; - - if (p_format & VS::ARRAY_COMPRESS_WEIGHTS) { - - attribs[i].type = GL_UNSIGNED_SHORT; - stride += 8; - attribs[i].normalized = GL_TRUE; - } else { - attribs[i].type = GL_FLOAT; - stride += 16; - attribs[i].normalized = GL_FALSE; - } - - } break; - case VS::ARRAY_INDEX: { - - attribs[i].size = 1; - - if (p_vertex_count >= (1 << 16)) { - attribs[i].type = GL_UNSIGNED_INT; - attribs[i].stride = 4; - } else { - attribs[i].type = GL_UNSIGNED_SHORT; - attribs[i].stride = 2; - } - - attribs[i].normalized = GL_FALSE; - - } break; - } - } - - for (int i = 0; i < VS::ARRAY_MAX - 1; i++) { - attribs[i].stride = stride; - } - - //validate sizes - - int array_size = stride * p_vertex_count; - int index_array_size = 0; - if (array.size() != array_size && array.size() + p_vertex_count * 2 == array_size) { - //old format, convert - array = PoolVector<uint8_t>(); - - array.resize(p_array.size() + p_vertex_count * 2); - - PoolVector<uint8_t>::Write w = array.write(); - PoolVector<uint8_t>::Read r = p_array.read(); - - uint16_t *w16 = (uint16_t *)w.ptr(); - const uint16_t *r16 = (uint16_t *)r.ptr(); - - uint16_t one = Math::make_half_float(1); - - for (int i = 0; i < p_vertex_count; i++) { - - *w16++ = *r16++; - *w16++ = *r16++; - *w16++ = *r16++; - *w16++ = one; - for (int j = 0; j < (stride / 2) - 4; j++) { - *w16++ = *r16++; - } - } - } - - ERR_FAIL_COND(array.size() != array_size); - - if (p_format & VS::ARRAY_FORMAT_INDEX) { - - index_array_size = attribs[VS::ARRAY_INDEX].stride * p_index_count; - } - - ERR_FAIL_COND(p_index_array.size() != index_array_size); - - ERR_FAIL_COND(p_blend_shapes.size() != mesh->blend_shape_count); - - for (int i = 0; i < p_blend_shapes.size(); i++) { - ERR_FAIL_COND(p_blend_shapes[i].size() != array_size); - } - - //ok all valid, create stuff - - Surface *surface = memnew(Surface); - - surface->active = true; - surface->array_len = p_vertex_count; - surface->index_array_len = p_index_count; - surface->array_byte_size = array.size(); - surface->index_array_byte_size = p_index_array.size(); - surface->primitive = p_primitive; - surface->mesh = mesh; - surface->format = p_format; - surface->skeleton_bone_aabb = p_bone_aabbs; - surface->skeleton_bone_used.resize(surface->skeleton_bone_aabb.size()); - surface->aabb = p_aabb; - surface->max_bone = p_bone_aabbs.size(); - surface->total_data_size += surface->array_byte_size + surface->index_array_byte_size; - - for (int i = 0; i < surface->skeleton_bone_used.size(); i++) { - if (surface->skeleton_bone_aabb[i].size.x < 0 || surface->skeleton_bone_aabb[i].size.y < 0 || surface->skeleton_bone_aabb[i].size.z < 0) { - surface->skeleton_bone_used.write[i] = false; - } else { - surface->skeleton_bone_used.write[i] = true; - } - } - - for (int i = 0; i < VS::ARRAY_MAX; i++) { - surface->attribs[i] = attribs[i]; - } - - { - - PoolVector<uint8_t>::Read vr = array.read(); - - glGenBuffers(1, &surface->vertex_id); - glBindBuffer(GL_ARRAY_BUFFER, surface->vertex_id); - glBufferData(GL_ARRAY_BUFFER, array_size, vr.ptr(), (p_format & VS::ARRAY_FLAG_USE_DYNAMIC_UPDATE) ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW); - glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind - - if (p_format & VS::ARRAY_FORMAT_INDEX) { - - PoolVector<uint8_t>::Read ir = p_index_array.read(); - - glGenBuffers(1, &surface->index_id); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, surface->index_id); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, index_array_size, ir.ptr(), GL_STATIC_DRAW); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); //unbind - } - - //generate arrays for faster state switching - - for (int ai = 0; ai < 2; ai++) { - - if (ai == 0) { - //for normal draw - glGenVertexArrays(1, &surface->array_id); - glBindVertexArray(surface->array_id); - glBindBuffer(GL_ARRAY_BUFFER, surface->vertex_id); - } else if (ai == 1) { - //for instancing draw (can be changed and no one cares) - glGenVertexArrays(1, &surface->instancing_array_id); - glBindVertexArray(surface->instancing_array_id); - glBindBuffer(GL_ARRAY_BUFFER, surface->vertex_id); - } - - for (int i = 0; i < VS::ARRAY_MAX - 1; i++) { - - if (!attribs[i].enabled) - continue; - - if (attribs[i].integer) { - glVertexAttribIPointer(attribs[i].index, attribs[i].size, attribs[i].type, attribs[i].stride, CAST_INT_TO_UCHAR_PTR(attribs[i].offset)); - } else { - glVertexAttribPointer(attribs[i].index, attribs[i].size, attribs[i].type, attribs[i].normalized, attribs[i].stride, CAST_INT_TO_UCHAR_PTR(attribs[i].offset)); - } - glEnableVertexAttribArray(attribs[i].index); - } - - if (surface->index_id) { - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, surface->index_id); - } - - glBindVertexArray(0); - glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - } - -#ifdef DEBUG_ENABLED - - if (config.generate_wireframes && p_primitive == VS::PRIMITIVE_TRIANGLES) { - //generate wireframes, this is used mostly by editor - PoolVector<uint32_t> wf_indices; - int index_count; - - if (p_format & VS::ARRAY_FORMAT_INDEX) { - - index_count = p_index_count * 2; - wf_indices.resize(index_count); - - PoolVector<uint8_t>::Read ir = p_index_array.read(); - PoolVector<uint32_t>::Write wr = wf_indices.write(); - - if (p_vertex_count < (1 << 16)) { - //read 16 bit indices - const uint16_t *src_idx = (const uint16_t *)ir.ptr(); - for (int i = 0; i + 5 < index_count; i += 6) { - - wr[i + 0] = src_idx[i / 2]; - wr[i + 1] = src_idx[i / 2 + 1]; - wr[i + 2] = src_idx[i / 2 + 1]; - wr[i + 3] = src_idx[i / 2 + 2]; - wr[i + 4] = src_idx[i / 2 + 2]; - wr[i + 5] = src_idx[i / 2]; - } - - } else { - - //read 16 bit indices - const uint32_t *src_idx = (const uint32_t *)ir.ptr(); - for (int i = 0; i + 5 < index_count; i += 6) { - - wr[i + 0] = src_idx[i / 2]; - wr[i + 1] = src_idx[i / 2 + 1]; - wr[i + 2] = src_idx[i / 2 + 1]; - wr[i + 3] = src_idx[i / 2 + 2]; - wr[i + 4] = src_idx[i / 2 + 2]; - wr[i + 5] = src_idx[i / 2]; - } - } - - } else { - - index_count = p_vertex_count * 2; - wf_indices.resize(index_count); - PoolVector<uint32_t>::Write wr = wf_indices.write(); - for (int i = 0; i + 5 < index_count; i += 6) { - - wr[i + 0] = i / 2; - wr[i + 1] = i / 2 + 1; - wr[i + 2] = i / 2 + 1; - wr[i + 3] = i / 2 + 2; - wr[i + 4] = i / 2 + 2; - wr[i + 5] = i / 2; - } - } - { - PoolVector<uint32_t>::Read ir = wf_indices.read(); - - glGenBuffers(1, &surface->index_wireframe_id); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, surface->index_wireframe_id); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, index_count * sizeof(uint32_t), ir.ptr(), GL_STATIC_DRAW); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); //unbind - - surface->index_wireframe_len = index_count; - } - - for (int ai = 0; ai < 2; ai++) { - - if (ai == 0) { - //for normal draw - glGenVertexArrays(1, &surface->array_wireframe_id); - glBindVertexArray(surface->array_wireframe_id); - glBindBuffer(GL_ARRAY_BUFFER, surface->vertex_id); - } else if (ai == 1) { - //for instancing draw (can be changed and no one cares) - glGenVertexArrays(1, &surface->instancing_array_wireframe_id); - glBindVertexArray(surface->instancing_array_wireframe_id); - glBindBuffer(GL_ARRAY_BUFFER, surface->vertex_id); - } - - for (int i = 0; i < VS::ARRAY_MAX - 1; i++) { - - if (!attribs[i].enabled) - continue; - - if (attribs[i].integer) { - glVertexAttribIPointer(attribs[i].index, attribs[i].size, attribs[i].type, attribs[i].stride, CAST_INT_TO_UCHAR_PTR(attribs[i].offset)); - } else { - glVertexAttribPointer(attribs[i].index, attribs[i].size, attribs[i].type, attribs[i].normalized, attribs[i].stride, CAST_INT_TO_UCHAR_PTR(attribs[i].offset)); - } - glEnableVertexAttribArray(attribs[i].index); - } - - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, surface->index_wireframe_id); - - glBindVertexArray(0); - glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - } - } - -#endif - } - - { - - //blend shapes - - for (int i = 0; i < p_blend_shapes.size(); i++) { - - Surface::BlendShape mt; - - PoolVector<uint8_t>::Read vr = p_blend_shapes[i].read(); - - surface->total_data_size += array_size; - - glGenBuffers(1, &mt.vertex_id); - glBindBuffer(GL_ARRAY_BUFFER, mt.vertex_id); - glBufferData(GL_ARRAY_BUFFER, array_size, vr.ptr(), GL_STATIC_DRAW); - glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind - - glGenVertexArrays(1, &mt.array_id); - glBindVertexArray(mt.array_id); - glBindBuffer(GL_ARRAY_BUFFER, mt.vertex_id); - - for (int j = 0; j < VS::ARRAY_MAX - 1; j++) { - - if (!attribs[j].enabled) - continue; - - if (attribs[j].integer) { - glVertexAttribIPointer(attribs[j].index, attribs[j].size, attribs[j].type, attribs[j].stride, CAST_INT_TO_UCHAR_PTR(attribs[j].offset)); - } else { - glVertexAttribPointer(attribs[j].index, attribs[j].size, attribs[j].type, attribs[j].normalized, attribs[j].stride, CAST_INT_TO_UCHAR_PTR(attribs[j].offset)); - } - glEnableVertexAttribArray(attribs[j].index); - } - - glBindVertexArray(0); - glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind - - surface->blend_shapes.push_back(mt); - } - } - - mesh->surfaces.push_back(surface); - mesh->instance_change_notify(true, true); - - info.vertex_mem += surface->total_data_size; -} - -void RasterizerStorageGLES3::mesh_set_blend_shape_count(RID p_mesh, int p_amount) { - - Mesh *mesh = mesh_owner.getornull(p_mesh); - ERR_FAIL_COND(!mesh); - - ERR_FAIL_COND(mesh->surfaces.size() != 0); - ERR_FAIL_COND(p_amount < 0); - - mesh->blend_shape_count = p_amount; - mesh->instance_change_notify(true, false); -} -int RasterizerStorageGLES3::mesh_get_blend_shape_count(RID p_mesh) const { - - const Mesh *mesh = mesh_owner.getornull(p_mesh); - ERR_FAIL_COND_V(!mesh, 0); - - return mesh->blend_shape_count; -} - -void RasterizerStorageGLES3::mesh_set_blend_shape_mode(RID p_mesh, VS::BlendShapeMode p_mode) { - - Mesh *mesh = mesh_owner.getornull(p_mesh); - ERR_FAIL_COND(!mesh); - - mesh->blend_shape_mode = p_mode; -} -VS::BlendShapeMode RasterizerStorageGLES3::mesh_get_blend_shape_mode(RID p_mesh) const { - - const Mesh *mesh = mesh_owner.getornull(p_mesh); - ERR_FAIL_COND_V(!mesh, VS::BLEND_SHAPE_MODE_NORMALIZED); - - return mesh->blend_shape_mode; -} - -void RasterizerStorageGLES3::mesh_surface_update_region(RID p_mesh, int p_surface, int p_offset, const PoolVector<uint8_t> &p_data) { - - Mesh *mesh = mesh_owner.getornull(p_mesh); - ERR_FAIL_COND(!mesh); - ERR_FAIL_INDEX(p_surface, mesh->surfaces.size()); - - int total_size = p_data.size(); - ERR_FAIL_COND(p_offset + total_size > mesh->surfaces[p_surface]->array_byte_size); - - PoolVector<uint8_t>::Read r = p_data.read(); - - glBindBuffer(GL_ARRAY_BUFFER, mesh->surfaces[p_surface]->vertex_id); - glBufferSubData(GL_ARRAY_BUFFER, p_offset, total_size, r.ptr()); - glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind -} - -void RasterizerStorageGLES3::mesh_surface_set_material(RID p_mesh, int p_surface, RID p_material) { - - Mesh *mesh = mesh_owner.getornull(p_mesh); - ERR_FAIL_COND(!mesh); - ERR_FAIL_INDEX(p_surface, mesh->surfaces.size()); - - if (mesh->surfaces[p_surface]->material == p_material) - return; - - if (mesh->surfaces[p_surface]->material.is_valid()) { - _material_remove_geometry(mesh->surfaces[p_surface]->material, mesh->surfaces[p_surface]); - } - - mesh->surfaces[p_surface]->material = p_material; - - if (mesh->surfaces[p_surface]->material.is_valid()) { - _material_add_geometry(mesh->surfaces[p_surface]->material, mesh->surfaces[p_surface]); - } - - mesh->instance_change_notify(false, true); -} -RID RasterizerStorageGLES3::mesh_surface_get_material(RID p_mesh, int p_surface) const { - - const Mesh *mesh = mesh_owner.getornull(p_mesh); - ERR_FAIL_COND_V(!mesh, RID()); - ERR_FAIL_INDEX_V(p_surface, mesh->surfaces.size(), RID()); - - return mesh->surfaces[p_surface]->material; -} - -int RasterizerStorageGLES3::mesh_surface_get_array_len(RID p_mesh, int p_surface) const { - - const Mesh *mesh = mesh_owner.getornull(p_mesh); - ERR_FAIL_COND_V(!mesh, 0); - ERR_FAIL_INDEX_V(p_surface, mesh->surfaces.size(), 0); - - return mesh->surfaces[p_surface]->array_len; -} -int RasterizerStorageGLES3::mesh_surface_get_array_index_len(RID p_mesh, int p_surface) const { - - const Mesh *mesh = mesh_owner.getornull(p_mesh); - ERR_FAIL_COND_V(!mesh, 0); - ERR_FAIL_INDEX_V(p_surface, mesh->surfaces.size(), 0); - - return mesh->surfaces[p_surface]->index_array_len; -} - -PoolVector<uint8_t> RasterizerStorageGLES3::mesh_surface_get_array(RID p_mesh, int p_surface) const { - - const Mesh *mesh = mesh_owner.getornull(p_mesh); - ERR_FAIL_COND_V(!mesh, PoolVector<uint8_t>()); - ERR_FAIL_INDEX_V(p_surface, mesh->surfaces.size(), PoolVector<uint8_t>()); - - Surface *surface = mesh->surfaces[p_surface]; - - PoolVector<uint8_t> ret; - ret.resize(surface->array_byte_size); - glBindBuffer(GL_ARRAY_BUFFER, surface->vertex_id); - -#if defined(GLES_OVER_GL) || defined(__EMSCRIPTEN__) - { - PoolVector<uint8_t>::Write w = ret.write(); - glGetBufferSubData(GL_ARRAY_BUFFER, 0, surface->array_byte_size, w.ptr()); - } -#else - void *data = glMapBufferRange(GL_ARRAY_BUFFER, 0, surface->array_byte_size, GL_MAP_READ_BIT); - ERR_FAIL_NULL_V(data, PoolVector<uint8_t>()); - { - PoolVector<uint8_t>::Write w = ret.write(); - copymem(w.ptr(), data, surface->array_byte_size); - } - glUnmapBuffer(GL_ARRAY_BUFFER); -#endif - - glBindBuffer(GL_ARRAY_BUFFER, 0); - return ret; -} - -PoolVector<uint8_t> RasterizerStorageGLES3::mesh_surface_get_index_array(RID p_mesh, int p_surface) const { - const Mesh *mesh = mesh_owner.getornull(p_mesh); - ERR_FAIL_COND_V(!mesh, PoolVector<uint8_t>()); - ERR_FAIL_INDEX_V(p_surface, mesh->surfaces.size(), PoolVector<uint8_t>()); - - Surface *surface = mesh->surfaces[p_surface]; - - PoolVector<uint8_t> ret; - ret.resize(surface->index_array_byte_size); - - if (surface->index_array_byte_size > 0) { - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, surface->index_id); - -#if defined(GLES_OVER_GL) || defined(__EMSCRIPTEN__) - { - PoolVector<uint8_t>::Write w = ret.write(); - glGetBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, surface->index_array_byte_size, w.ptr()); - } -#else - void *data = glMapBufferRange(GL_ELEMENT_ARRAY_BUFFER, 0, surface->index_array_byte_size, GL_MAP_READ_BIT); - ERR_FAIL_NULL_V(data, PoolVector<uint8_t>()); - { - PoolVector<uint8_t>::Write w = ret.write(); - copymem(w.ptr(), data, surface->index_array_byte_size); - } - glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER); -#endif - - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - } - - return ret; -} - -uint32_t RasterizerStorageGLES3::mesh_surface_get_format(RID p_mesh, int p_surface) const { - - const Mesh *mesh = mesh_owner.getornull(p_mesh); - - ERR_FAIL_COND_V(!mesh, 0); - ERR_FAIL_INDEX_V(p_surface, mesh->surfaces.size(), 0); - - return mesh->surfaces[p_surface]->format; -} - -VS::PrimitiveType RasterizerStorageGLES3::mesh_surface_get_primitive_type(RID p_mesh, int p_surface) const { - - const Mesh *mesh = mesh_owner.getornull(p_mesh); - ERR_FAIL_COND_V(!mesh, VS::PRIMITIVE_MAX); - ERR_FAIL_INDEX_V(p_surface, mesh->surfaces.size(), VS::PRIMITIVE_MAX); - - return mesh->surfaces[p_surface]->primitive; -} - -AABB RasterizerStorageGLES3::mesh_surface_get_aabb(RID p_mesh, int p_surface) const { - - const Mesh *mesh = mesh_owner.getornull(p_mesh); - ERR_FAIL_COND_V(!mesh, AABB()); - ERR_FAIL_INDEX_V(p_surface, mesh->surfaces.size(), AABB()); - - return mesh->surfaces[p_surface]->aabb; -} -Vector<PoolVector<uint8_t> > RasterizerStorageGLES3::mesh_surface_get_blend_shapes(RID p_mesh, int p_surface) const { - - const Mesh *mesh = mesh_owner.getornull(p_mesh); - ERR_FAIL_COND_V(!mesh, Vector<PoolVector<uint8_t> >()); - ERR_FAIL_INDEX_V(p_surface, mesh->surfaces.size(), Vector<PoolVector<uint8_t> >()); - - Vector<PoolVector<uint8_t> > bsarr; - - for (int i = 0; i < mesh->surfaces[p_surface]->blend_shapes.size(); i++) { - - PoolVector<uint8_t> ret; - ret.resize(mesh->surfaces[p_surface]->array_byte_size); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh->surfaces[p_surface]->blend_shapes[i].vertex_id); - -#if defined(GLES_OVER_GL) || defined(__EMSCRIPTEN__) - { - PoolVector<uint8_t>::Write w = ret.write(); - glGetBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, mesh->surfaces[p_surface]->array_byte_size, w.ptr()); - } -#else - void *data = glMapBufferRange(GL_ELEMENT_ARRAY_BUFFER, 0, mesh->surfaces[p_surface]->array_byte_size, GL_MAP_READ_BIT); - ERR_FAIL_COND_V(!data, Vector<PoolVector<uint8_t> >()); - { - PoolVector<uint8_t>::Write w = ret.write(); - copymem(w.ptr(), data, mesh->surfaces[p_surface]->array_byte_size); - } - glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER); -#endif - - bsarr.push_back(ret); - } - - return bsarr; -} - -Vector<AABB> RasterizerStorageGLES3::mesh_surface_get_skeleton_aabb(RID p_mesh, int p_surface) const { - - const Mesh *mesh = mesh_owner.getornull(p_mesh); - ERR_FAIL_COND_V(!mesh, Vector<AABB>()); - ERR_FAIL_INDEX_V(p_surface, mesh->surfaces.size(), Vector<AABB>()); - - return mesh->surfaces[p_surface]->skeleton_bone_aabb; -} - -void RasterizerStorageGLES3::mesh_remove_surface(RID p_mesh, int p_surface) { - - Mesh *mesh = mesh_owner.getornull(p_mesh); - ERR_FAIL_COND(!mesh); - ERR_FAIL_INDEX(p_surface, mesh->surfaces.size()); - - Surface *surface = mesh->surfaces[p_surface]; - - if (surface->material.is_valid()) { - _material_remove_geometry(surface->material, mesh->surfaces[p_surface]); - } - - glDeleteBuffers(1, &surface->vertex_id); - if (surface->index_id) { - glDeleteBuffers(1, &surface->index_id); - } - - glDeleteVertexArrays(1, &surface->array_id); - glDeleteVertexArrays(1, &surface->instancing_array_id); - - for (int i = 0; i < surface->blend_shapes.size(); i++) { - - glDeleteBuffers(1, &surface->blend_shapes[i].vertex_id); - glDeleteVertexArrays(1, &surface->blend_shapes[i].array_id); - } - - if (surface->index_wireframe_id) { - glDeleteBuffers(1, &surface->index_wireframe_id); - glDeleteVertexArrays(1, &surface->array_wireframe_id); - glDeleteVertexArrays(1, &surface->instancing_array_wireframe_id); - } - - info.vertex_mem -= surface->total_data_size; - - memdelete(surface); - - mesh->surfaces.remove(p_surface); - - mesh->instance_change_notify(true, true); -} - -int RasterizerStorageGLES3::mesh_get_surface_count(RID p_mesh) const { - - const Mesh *mesh = mesh_owner.getornull(p_mesh); - ERR_FAIL_COND_V(!mesh, 0); - return mesh->surfaces.size(); -} - -void RasterizerStorageGLES3::mesh_set_custom_aabb(RID p_mesh, const AABB &p_aabb) { - - Mesh *mesh = mesh_owner.getornull(p_mesh); - ERR_FAIL_COND(!mesh); - - mesh->custom_aabb = p_aabb; - mesh->instance_change_notify(true, false); -} - -AABB RasterizerStorageGLES3::mesh_get_custom_aabb(RID p_mesh) const { - - const Mesh *mesh = mesh_owner.getornull(p_mesh); - ERR_FAIL_COND_V(!mesh, AABB()); - - return mesh->custom_aabb; -} - -AABB RasterizerStorageGLES3::mesh_get_aabb(RID p_mesh, RID p_skeleton) const { - - Mesh *mesh = mesh_owner.get(p_mesh); - ERR_FAIL_COND_V(!mesh, AABB()); - - if (mesh->custom_aabb != AABB()) { - return mesh->custom_aabb; - } - - Skeleton *sk = NULL; - if (p_skeleton.is_valid()) { - sk = skeleton_owner.get(p_skeleton); - } - - AABB aabb; - - if (sk && sk->size != 0) { - - for (int i = 0; i < mesh->surfaces.size(); i++) { - - AABB laabb; - if ((mesh->surfaces[i]->format & VS::ARRAY_FORMAT_BONES) && mesh->surfaces[i]->skeleton_bone_aabb.size()) { - - int bs = mesh->surfaces[i]->skeleton_bone_aabb.size(); - const AABB *skbones = mesh->surfaces[i]->skeleton_bone_aabb.ptr(); - const bool *skused = mesh->surfaces[i]->skeleton_bone_used.ptr(); - - int sbs = sk->size; - ERR_CONTINUE(bs > sbs); - const float *texture = sk->skel_texture.ptr(); - - bool first = true; - if (sk->use_2d) { - for (int j = 0; j < bs; j++) { - - if (!skused[j]) - continue; - - int base_ofs = ((j / 256) * 256) * 2 * 4 + (j % 256) * 4; - - Transform mtx; - - mtx.basis[0].x = texture[base_ofs + 0]; - mtx.basis[0].y = texture[base_ofs + 1]; - mtx.origin.x = texture[base_ofs + 3]; - base_ofs += 256 * 4; - mtx.basis[1].x = texture[base_ofs + 0]; - mtx.basis[1].y = texture[base_ofs + 1]; - mtx.origin.y = texture[base_ofs + 3]; - - AABB baabb = mtx.xform(skbones[j]); - - if (first) { - laabb = baabb; - first = false; - } else { - laabb.merge_with(baabb); - } - } - } else { - for (int j = 0; j < bs; j++) { - - if (!skused[j]) - continue; - - int base_ofs = ((j / 256) * 256) * 3 * 4 + (j % 256) * 4; - - Transform mtx; - - mtx.basis[0].x = texture[base_ofs + 0]; - mtx.basis[0].y = texture[base_ofs + 1]; - mtx.basis[0].z = texture[base_ofs + 2]; - mtx.origin.x = texture[base_ofs + 3]; - base_ofs += 256 * 4; - mtx.basis[1].x = texture[base_ofs + 0]; - mtx.basis[1].y = texture[base_ofs + 1]; - mtx.basis[1].z = texture[base_ofs + 2]; - mtx.origin.y = texture[base_ofs + 3]; - base_ofs += 256 * 4; - mtx.basis[2].x = texture[base_ofs + 0]; - mtx.basis[2].y = texture[base_ofs + 1]; - mtx.basis[2].z = texture[base_ofs + 2]; - mtx.origin.z = texture[base_ofs + 3]; - - AABB baabb = mtx.xform(skbones[j]); - if (first) { - laabb = baabb; - first = false; - } else { - laabb.merge_with(baabb); - } - } - } - - } else { - - laabb = mesh->surfaces[i]->aabb; - } - - if (i == 0) - aabb = laabb; - else - aabb.merge_with(laabb); - } - } else { - - for (int i = 0; i < mesh->surfaces.size(); i++) { - - if (i == 0) - aabb = mesh->surfaces[i]->aabb; - else - aabb.merge_with(mesh->surfaces[i]->aabb); - } - } - - return aabb; -} -void RasterizerStorageGLES3::mesh_clear(RID p_mesh) { - - Mesh *mesh = mesh_owner.getornull(p_mesh); - ERR_FAIL_COND(!mesh); - - while (mesh->surfaces.size()) { - mesh_remove_surface(p_mesh, 0); - } -} - -void RasterizerStorageGLES3::mesh_render_blend_shapes(Surface *s, const float *p_weights) { - - glBindVertexArray(s->array_id); - - BlendShapeShaderGLES3::Conditionals cond[VS::ARRAY_MAX - 1] = { - BlendShapeShaderGLES3::ENABLE_NORMAL, //will be ignored - BlendShapeShaderGLES3::ENABLE_NORMAL, - BlendShapeShaderGLES3::ENABLE_TANGENT, - BlendShapeShaderGLES3::ENABLE_COLOR, - BlendShapeShaderGLES3::ENABLE_UV, - BlendShapeShaderGLES3::ENABLE_UV2, - BlendShapeShaderGLES3::ENABLE_SKELETON, - BlendShapeShaderGLES3::ENABLE_SKELETON, - }; - - int stride = 0; - - if (s->format & VS::ARRAY_FLAG_USE_2D_VERTICES) { - stride = 2 * 4; - } else { - stride = 3 * 4; - } - - static const int sizes[VS::ARRAY_MAX - 1] = { - 3 * 4, - 3 * 4, - 4 * 4, - 4 * 4, - 2 * 4, - 2 * 4, - 4 * 4, - 4 * 4 - }; - - for (int i = 1; i < VS::ARRAY_MAX - 1; i++) { - shaders.blend_shapes.set_conditional(cond[i], s->format & (1 << i)); //enable conditional for format - if (s->format & (1 << i)) { - stride += sizes[i]; - } - } - - //copy all first - float base_weight = 1.0; - - int mtc = s->blend_shapes.size(); - - if (s->mesh->blend_shape_mode == VS::BLEND_SHAPE_MODE_NORMALIZED) { - - for (int i = 0; i < mtc; i++) { - base_weight -= p_weights[i]; - } - } - - shaders.blend_shapes.set_conditional(BlendShapeShaderGLES3::ENABLE_BLEND, false); //first pass does not blend - shaders.blend_shapes.set_conditional(BlendShapeShaderGLES3::USE_2D_VERTEX, s->format & VS::ARRAY_FLAG_USE_2D_VERTICES); //use 2D vertices if needed - - shaders.blend_shapes.bind(); - - shaders.blend_shapes.set_uniform(BlendShapeShaderGLES3::BLEND_AMOUNT, base_weight); - glEnable(GL_RASTERIZER_DISCARD); - - glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, resources.transform_feedback_buffers[0]); - glBeginTransformFeedback(GL_POINTS); - glDrawArrays(GL_POINTS, 0, s->array_len); - glEndTransformFeedback(); - - shaders.blend_shapes.set_conditional(BlendShapeShaderGLES3::ENABLE_BLEND, true); //first pass does not blend - shaders.blend_shapes.bind(); - - for (int ti = 0; ti < mtc; ti++) { - float weight = p_weights[ti]; - - if (weight < 0.00001) //not bother with this one - continue; - - glBindVertexArray(s->blend_shapes[ti].array_id); - glBindBuffer(GL_ARRAY_BUFFER, resources.transform_feedback_buffers[0]); - glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, resources.transform_feedback_buffers[1]); - - shaders.blend_shapes.set_uniform(BlendShapeShaderGLES3::BLEND_AMOUNT, weight); - - int ofs = 0; - for (int i = 0; i < VS::ARRAY_MAX - 1; i++) { - - if (s->format & (1 << i)) { - glEnableVertexAttribArray(i + 8); - switch (i) { - - case VS::ARRAY_VERTEX: { - if (s->format & VS::ARRAY_FLAG_USE_2D_VERTICES) { - glVertexAttribPointer(i + 8, 2, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(ofs)); - ofs += 2 * 4; - } else { - glVertexAttribPointer(i + 8, 3, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(ofs)); - ofs += 3 * 4; - } - } break; - case VS::ARRAY_NORMAL: { - glVertexAttribPointer(i + 8, 3, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(ofs)); - ofs += 3 * 4; - } break; - case VS::ARRAY_TANGENT: { - glVertexAttribPointer(i + 8, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(ofs)); - ofs += 4 * 4; - - } break; - case VS::ARRAY_COLOR: { - glVertexAttribPointer(i + 8, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(ofs)); - ofs += 4 * 4; - - } break; - case VS::ARRAY_TEX_UV: { - glVertexAttribPointer(i + 8, 2, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(ofs)); - ofs += 2 * 4; - - } break; - case VS::ARRAY_TEX_UV2: { - glVertexAttribPointer(i + 8, 2, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(ofs)); - ofs += 2 * 4; - - } break; - case VS::ARRAY_BONES: { - glVertexAttribIPointer(i + 8, 4, GL_UNSIGNED_INT, stride, CAST_INT_TO_UCHAR_PTR(ofs)); - ofs += 4 * 4; - - } break; - case VS::ARRAY_WEIGHTS: { - glVertexAttribPointer(i + 8, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(ofs)); - ofs += 4 * 4; - - } break; - } - - } else { - glDisableVertexAttribArray(i + 8); - } - } - - glBeginTransformFeedback(GL_POINTS); - glDrawArrays(GL_POINTS, 0, s->array_len); - glEndTransformFeedback(); - - SWAP(resources.transform_feedback_buffers[0], resources.transform_feedback_buffers[1]); - } - - glDisable(GL_RASTERIZER_DISCARD); - glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, 0); - - glBindVertexArray(resources.transform_feedback_array); - glBindBuffer(GL_ARRAY_BUFFER, resources.transform_feedback_buffers[0]); - - int ofs = 0; - for (int i = 0; i < VS::ARRAY_MAX - 1; i++) { - - if (s->format & (1 << i)) { - glEnableVertexAttribArray(i); - switch (i) { - - case VS::ARRAY_VERTEX: { - if (s->format & VS::ARRAY_FLAG_USE_2D_VERTICES) { - glVertexAttribPointer(i, 2, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(ofs)); - ofs += 2 * 4; - } else { - glVertexAttribPointer(i, 3, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(ofs)); - ofs += 3 * 4; - } - } break; - case VS::ARRAY_NORMAL: { - glVertexAttribPointer(i, 3, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(ofs)); - ofs += 3 * 4; - } break; - case VS::ARRAY_TANGENT: { - glVertexAttribPointer(i, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(ofs)); - ofs += 4 * 4; - - } break; - case VS::ARRAY_COLOR: { - glVertexAttribPointer(i, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(ofs)); - ofs += 4 * 4; - - } break; - case VS::ARRAY_TEX_UV: { - glVertexAttribPointer(i, 2, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(ofs)); - ofs += 2 * 4; - - } break; - case VS::ARRAY_TEX_UV2: { - glVertexAttribPointer(i, 2, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(ofs)); - ofs += 2 * 4; - - } break; - case VS::ARRAY_BONES: { - glVertexAttribIPointer(i, 4, GL_UNSIGNED_INT, stride, CAST_INT_TO_UCHAR_PTR(ofs)); - ofs += 4 * 4; - - } break; - case VS::ARRAY_WEIGHTS: { - glVertexAttribPointer(i, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(ofs)); - ofs += 4 * 4; - - } break; - } - - } else { - glDisableVertexAttribArray(i); - } - } - - if (s->index_array_len) { - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, s->index_id); - } -} - -/* MULTIMESH API */ - -RID RasterizerStorageGLES3::multimesh_create() { - - MultiMesh *multimesh = memnew(MultiMesh); - return multimesh_owner.make_rid(multimesh); -} - -void RasterizerStorageGLES3::multimesh_allocate(RID p_multimesh, int p_instances, VS::MultimeshTransformFormat p_transform_format, VS::MultimeshColorFormat p_color_format, VS::MultimeshCustomDataFormat p_data_format) { - - MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); - ERR_FAIL_COND(!multimesh); - - if (multimesh->size == p_instances && multimesh->transform_format == p_transform_format && multimesh->color_format == p_color_format && multimesh->custom_data_format == p_data_format) - return; - - if (multimesh->buffer) { - glDeleteBuffers(1, &multimesh->buffer); - multimesh->data.resize(0); - multimesh->buffer = 0; - } - - multimesh->size = p_instances; - multimesh->transform_format = p_transform_format; - multimesh->color_format = p_color_format; - multimesh->custom_data_format = p_data_format; - - if (multimesh->size) { - - if (multimesh->transform_format == VS::MULTIMESH_TRANSFORM_2D) { - multimesh->xform_floats = 8; - } else { - multimesh->xform_floats = 12; - } - - if (multimesh->color_format == VS::MULTIMESH_COLOR_8BIT) { - multimesh->color_floats = 1; - } else if (multimesh->color_format == VS::MULTIMESH_COLOR_FLOAT) { - multimesh->color_floats = 4; - } else { - multimesh->color_floats = 0; - } - - if (multimesh->custom_data_format == VS::MULTIMESH_CUSTOM_DATA_8BIT) { - multimesh->custom_data_floats = 1; - } else if (multimesh->custom_data_format == VS::MULTIMESH_CUSTOM_DATA_FLOAT) { - multimesh->custom_data_floats = 4; - } else { - multimesh->custom_data_floats = 0; - } - - int format_floats = multimesh->color_floats + multimesh->xform_floats + multimesh->custom_data_floats; - - multimesh->data.resize(format_floats * p_instances); - - float *dataptr = multimesh->data.ptrw(); - - for (int i = 0; i < p_instances * format_floats; i += format_floats) { - - int color_from = 0; - int custom_data_from = 0; - - if (multimesh->transform_format == VS::MULTIMESH_TRANSFORM_2D) { - dataptr[i + 0] = 1.0; - dataptr[i + 1] = 0.0; - dataptr[i + 2] = 0.0; - dataptr[i + 3] = 0.0; - dataptr[i + 4] = 0.0; - dataptr[i + 5] = 1.0; - dataptr[i + 6] = 0.0; - dataptr[i + 7] = 0.0; - color_from = 8; - custom_data_from = 8; - } else { - dataptr[i + 0] = 1.0; - dataptr[i + 1] = 0.0; - dataptr[i + 2] = 0.0; - dataptr[i + 3] = 0.0; - dataptr[i + 4] = 0.0; - dataptr[i + 5] = 1.0; - dataptr[i + 6] = 0.0; - dataptr[i + 7] = 0.0; - dataptr[i + 8] = 0.0; - dataptr[i + 9] = 0.0; - dataptr[i + 10] = 1.0; - dataptr[i + 11] = 0.0; - color_from = 12; - custom_data_from = 12; - } - - if (multimesh->color_format == VS::MULTIMESH_COLOR_NONE) { - //none - } else if (multimesh->color_format == VS::MULTIMESH_COLOR_8BIT) { - - union { - uint32_t colu; - float colf; - } cu; - - cu.colu = 0xFFFFFFFF; - dataptr[i + color_from + 0] = cu.colf; - custom_data_from = color_from + 1; - - } else if (multimesh->color_format == VS::MULTIMESH_COLOR_FLOAT) { - dataptr[i + color_from + 0] = 1.0; - dataptr[i + color_from + 1] = 1.0; - dataptr[i + color_from + 2] = 1.0; - dataptr[i + color_from + 3] = 1.0; - custom_data_from = color_from + 4; - } - - if (multimesh->custom_data_format == VS::MULTIMESH_CUSTOM_DATA_NONE) { - //none - } else if (multimesh->custom_data_format == VS::MULTIMESH_CUSTOM_DATA_8BIT) { - - union { - uint32_t colu; - float colf; - } cu; - - cu.colu = 0; - dataptr[i + custom_data_from + 0] = cu.colf; - - } else if (multimesh->custom_data_format == VS::MULTIMESH_CUSTOM_DATA_FLOAT) { - dataptr[i + custom_data_from + 0] = 0.0; - dataptr[i + custom_data_from + 1] = 0.0; - dataptr[i + custom_data_from + 2] = 0.0; - dataptr[i + custom_data_from + 3] = 0.0; - } - } - - glGenBuffers(1, &multimesh->buffer); - glBindBuffer(GL_ARRAY_BUFFER, multimesh->buffer); - glBufferData(GL_ARRAY_BUFFER, multimesh->data.size() * sizeof(float), NULL, GL_STATIC_DRAW); - glBindBuffer(GL_ARRAY_BUFFER, 0); - } - - multimesh->dirty_data = true; - multimesh->dirty_aabb = true; - - if (!multimesh->update_list.in_list()) { - multimesh_update_list.add(&multimesh->update_list); - } -} - -int RasterizerStorageGLES3::multimesh_get_instance_count(RID p_multimesh) const { - - MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); - ERR_FAIL_COND_V(!multimesh, 0); - - return multimesh->size; -} - -void RasterizerStorageGLES3::multimesh_set_mesh(RID p_multimesh, RID p_mesh) { - - MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); - ERR_FAIL_COND(!multimesh); - - if (multimesh->mesh.is_valid()) { - Mesh *mesh = mesh_owner.getornull(multimesh->mesh); - if (mesh) { - mesh->multimeshes.remove(&multimesh->mesh_list); - } - } - - multimesh->mesh = p_mesh; - - if (multimesh->mesh.is_valid()) { - Mesh *mesh = mesh_owner.getornull(multimesh->mesh); - if (mesh) { - mesh->multimeshes.add(&multimesh->mesh_list); - } - } - - multimesh->dirty_aabb = true; - - if (!multimesh->update_list.in_list()) { - multimesh_update_list.add(&multimesh->update_list); - } -} - -void RasterizerStorageGLES3::multimesh_instance_set_transform(RID p_multimesh, int p_index, const Transform &p_transform) { - - MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); - ERR_FAIL_COND(!multimesh); - ERR_FAIL_INDEX(p_index, multimesh->size); - ERR_FAIL_COND(multimesh->transform_format == VS::MULTIMESH_TRANSFORM_2D); - - int stride = multimesh->color_floats + multimesh->xform_floats + multimesh->custom_data_floats; - float *dataptr = &multimesh->data.write[stride * p_index]; - - dataptr[0] = p_transform.basis.elements[0][0]; - dataptr[1] = p_transform.basis.elements[0][1]; - dataptr[2] = p_transform.basis.elements[0][2]; - dataptr[3] = p_transform.origin.x; - dataptr[4] = p_transform.basis.elements[1][0]; - dataptr[5] = p_transform.basis.elements[1][1]; - dataptr[6] = p_transform.basis.elements[1][2]; - dataptr[7] = p_transform.origin.y; - dataptr[8] = p_transform.basis.elements[2][0]; - dataptr[9] = p_transform.basis.elements[2][1]; - dataptr[10] = p_transform.basis.elements[2][2]; - dataptr[11] = p_transform.origin.z; - - multimesh->dirty_data = true; - multimesh->dirty_aabb = true; - - if (!multimesh->update_list.in_list()) { - multimesh_update_list.add(&multimesh->update_list); - } -} - -void RasterizerStorageGLES3::multimesh_instance_set_transform_2d(RID p_multimesh, int p_index, const Transform2D &p_transform) { - - MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); - ERR_FAIL_COND(!multimesh); - ERR_FAIL_INDEX(p_index, multimesh->size); - ERR_FAIL_COND(multimesh->transform_format == VS::MULTIMESH_TRANSFORM_3D); - - int stride = multimesh->color_floats + multimesh->xform_floats + multimesh->custom_data_floats; - float *dataptr = &multimesh->data.write[stride * p_index]; - - dataptr[0] = p_transform.elements[0][0]; - dataptr[1] = p_transform.elements[1][0]; - dataptr[2] = 0; - dataptr[3] = p_transform.elements[2][0]; - dataptr[4] = p_transform.elements[0][1]; - dataptr[5] = p_transform.elements[1][1]; - dataptr[6] = 0; - dataptr[7] = p_transform.elements[2][1]; - - multimesh->dirty_data = true; - multimesh->dirty_aabb = true; - - if (!multimesh->update_list.in_list()) { - multimesh_update_list.add(&multimesh->update_list); - } -} -void RasterizerStorageGLES3::multimesh_instance_set_color(RID p_multimesh, int p_index, const Color &p_color) { - - MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); - ERR_FAIL_COND(!multimesh); - ERR_FAIL_INDEX(p_index, multimesh->size); - ERR_FAIL_COND(multimesh->color_format == VS::MULTIMESH_COLOR_NONE); - ERR_FAIL_INDEX(multimesh->color_format, VS::MULTIMESH_COLOR_MAX); - - int stride = multimesh->color_floats + multimesh->xform_floats + multimesh->custom_data_floats; - float *dataptr = &multimesh->data.write[stride * p_index + multimesh->xform_floats]; - - if (multimesh->color_format == VS::MULTIMESH_COLOR_8BIT) { - - uint8_t *data8 = (uint8_t *)dataptr; - data8[0] = CLAMP(p_color.r * 255.0, 0, 255); - data8[1] = CLAMP(p_color.g * 255.0, 0, 255); - data8[2] = CLAMP(p_color.b * 255.0, 0, 255); - data8[3] = CLAMP(p_color.a * 255.0, 0, 255); - - } else if (multimesh->color_format == VS::MULTIMESH_COLOR_FLOAT) { - dataptr[0] = p_color.r; - dataptr[1] = p_color.g; - dataptr[2] = p_color.b; - dataptr[3] = p_color.a; - } - - multimesh->dirty_data = true; - multimesh->dirty_aabb = true; - - if (!multimesh->update_list.in_list()) { - multimesh_update_list.add(&multimesh->update_list); - } -} - -void RasterizerStorageGLES3::multimesh_instance_set_custom_data(RID p_multimesh, int p_index, const Color &p_custom_data) { - - MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); - ERR_FAIL_COND(!multimesh); - ERR_FAIL_INDEX(p_index, multimesh->size); - ERR_FAIL_COND(multimesh->custom_data_format == VS::MULTIMESH_CUSTOM_DATA_NONE); - ERR_FAIL_INDEX(multimesh->custom_data_format, VS::MULTIMESH_CUSTOM_DATA_MAX); - - int stride = multimesh->color_floats + multimesh->xform_floats + multimesh->custom_data_floats; - float *dataptr = &multimesh->data.write[stride * p_index + multimesh->xform_floats + multimesh->color_floats]; - - if (multimesh->custom_data_format == VS::MULTIMESH_CUSTOM_DATA_8BIT) { - - uint8_t *data8 = (uint8_t *)dataptr; - data8[0] = CLAMP(p_custom_data.r * 255.0, 0, 255); - data8[1] = CLAMP(p_custom_data.g * 255.0, 0, 255); - data8[2] = CLAMP(p_custom_data.b * 255.0, 0, 255); - data8[3] = CLAMP(p_custom_data.a * 255.0, 0, 255); - - } else if (multimesh->custom_data_format == VS::MULTIMESH_CUSTOM_DATA_FLOAT) { - dataptr[0] = p_custom_data.r; - dataptr[1] = p_custom_data.g; - dataptr[2] = p_custom_data.b; - dataptr[3] = p_custom_data.a; - } - - multimesh->dirty_data = true; - multimesh->dirty_aabb = true; - - if (!multimesh->update_list.in_list()) { - multimesh_update_list.add(&multimesh->update_list); - } -} -RID RasterizerStorageGLES3::multimesh_get_mesh(RID p_multimesh) const { - - MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); - ERR_FAIL_COND_V(!multimesh, RID()); - - return multimesh->mesh; -} - -Transform RasterizerStorageGLES3::multimesh_instance_get_transform(RID p_multimesh, int p_index) const { - - MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); - ERR_FAIL_COND_V(!multimesh, Transform()); - ERR_FAIL_INDEX_V(p_index, multimesh->size, Transform()); - ERR_FAIL_COND_V(multimesh->transform_format == VS::MULTIMESH_TRANSFORM_2D, Transform()); - - int stride = multimesh->color_floats + multimesh->xform_floats + multimesh->custom_data_floats; - float *dataptr = &multimesh->data.write[stride * p_index]; - - Transform xform; - - xform.basis.elements[0][0] = dataptr[0]; - xform.basis.elements[0][1] = dataptr[1]; - xform.basis.elements[0][2] = dataptr[2]; - xform.origin.x = dataptr[3]; - xform.basis.elements[1][0] = dataptr[4]; - xform.basis.elements[1][1] = dataptr[5]; - xform.basis.elements[1][2] = dataptr[6]; - xform.origin.y = dataptr[7]; - xform.basis.elements[2][0] = dataptr[8]; - xform.basis.elements[2][1] = dataptr[9]; - xform.basis.elements[2][2] = dataptr[10]; - xform.origin.z = dataptr[11]; - - return xform; -} -Transform2D RasterizerStorageGLES3::multimesh_instance_get_transform_2d(RID p_multimesh, int p_index) const { - - MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); - ERR_FAIL_COND_V(!multimesh, Transform2D()); - ERR_FAIL_INDEX_V(p_index, multimesh->size, Transform2D()); - ERR_FAIL_COND_V(multimesh->transform_format == VS::MULTIMESH_TRANSFORM_3D, Transform2D()); - - int stride = multimesh->color_floats + multimesh->xform_floats + multimesh->custom_data_floats; - float *dataptr = &multimesh->data.write[stride * p_index]; - - Transform2D xform; - - xform.elements[0][0] = dataptr[0]; - xform.elements[1][0] = dataptr[1]; - xform.elements[2][0] = dataptr[3]; - xform.elements[0][1] = dataptr[4]; - xform.elements[1][1] = dataptr[5]; - xform.elements[2][1] = dataptr[7]; - - return xform; -} - -Color RasterizerStorageGLES3::multimesh_instance_get_color(RID p_multimesh, int p_index) const { - MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); - ERR_FAIL_COND_V(!multimesh, Color()); - ERR_FAIL_INDEX_V(p_index, multimesh->size, Color()); - ERR_FAIL_COND_V(multimesh->color_format == VS::MULTIMESH_COLOR_NONE, Color()); - ERR_FAIL_INDEX_V(multimesh->color_format, VS::MULTIMESH_COLOR_MAX, Color()); - - int stride = multimesh->color_floats + multimesh->xform_floats + multimesh->custom_data_floats; - float *dataptr = &multimesh->data.write[stride * p_index + multimesh->xform_floats]; - - if (multimesh->color_format == VS::MULTIMESH_COLOR_8BIT) { - union { - uint32_t colu; - float colf; - } cu; - - cu.colf = dataptr[0]; - - return Color::hex(BSWAP32(cu.colu)); - - } else if (multimesh->color_format == VS::MULTIMESH_COLOR_FLOAT) { - Color c; - c.r = dataptr[0]; - c.g = dataptr[1]; - c.b = dataptr[2]; - c.a = dataptr[3]; - - return c; - } - - return Color(); -} - -Color RasterizerStorageGLES3::multimesh_instance_get_custom_data(RID p_multimesh, int p_index) const { - - MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); - ERR_FAIL_COND_V(!multimesh, Color()); - ERR_FAIL_INDEX_V(p_index, multimesh->size, Color()); - ERR_FAIL_COND_V(multimesh->custom_data_format == VS::MULTIMESH_CUSTOM_DATA_NONE, Color()); - ERR_FAIL_INDEX_V(multimesh->custom_data_format, VS::MULTIMESH_CUSTOM_DATA_MAX, Color()); - - int stride = multimesh->color_floats + multimesh->xform_floats + multimesh->custom_data_floats; - float *dataptr = &multimesh->data.write[stride * p_index + multimesh->xform_floats + multimesh->color_floats]; - - if (multimesh->custom_data_format == VS::MULTIMESH_CUSTOM_DATA_8BIT) { - union { - uint32_t colu; - float colf; - } cu; - - cu.colf = dataptr[0]; - - return Color::hex(BSWAP32(cu.colu)); - - } else if (multimesh->custom_data_format == VS::MULTIMESH_CUSTOM_DATA_FLOAT) { - Color c; - c.r = dataptr[0]; - c.g = dataptr[1]; - c.b = dataptr[2]; - c.a = dataptr[3]; - - return c; - } - - return Color(); -} - -void RasterizerStorageGLES3::multimesh_set_as_bulk_array(RID p_multimesh, const PoolVector<float> &p_array) { - - MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); - ERR_FAIL_COND(!multimesh); - ERR_FAIL_COND(!multimesh->data.ptr()); - - int dsize = multimesh->data.size(); - - ERR_FAIL_COND(dsize != p_array.size()); - - PoolVector<float>::Read r = p_array.read(); - copymem(multimesh->data.ptrw(), r.ptr(), dsize * sizeof(float)); - - multimesh->dirty_data = true; - multimesh->dirty_aabb = true; - - if (!multimesh->update_list.in_list()) { - multimesh_update_list.add(&multimesh->update_list); - } -} - -void RasterizerStorageGLES3::multimesh_set_visible_instances(RID p_multimesh, int p_visible) { - - MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); - ERR_FAIL_COND(!multimesh); - - multimesh->visible_instances = p_visible; -} -int RasterizerStorageGLES3::multimesh_get_visible_instances(RID p_multimesh) const { - - MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); - ERR_FAIL_COND_V(!multimesh, -1); - - return multimesh->visible_instances; -} - -AABB RasterizerStorageGLES3::multimesh_get_aabb(RID p_multimesh) const { - - MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); - ERR_FAIL_COND_V(!multimesh, AABB()); - - const_cast<RasterizerStorageGLES3 *>(this)->update_dirty_multimeshes(); //update pending AABBs - - return multimesh->aabb; -} - -void RasterizerStorageGLES3::update_dirty_multimeshes() { - - while (multimesh_update_list.first()) { - - MultiMesh *multimesh = multimesh_update_list.first()->self(); - - if (multimesh->size && multimesh->dirty_data) { - - glBindBuffer(GL_ARRAY_BUFFER, multimesh->buffer); - glBufferSubData(GL_ARRAY_BUFFER, 0, multimesh->data.size() * sizeof(float), multimesh->data.ptr()); - glBindBuffer(GL_ARRAY_BUFFER, 0); - } - - if (multimesh->size && multimesh->dirty_aabb) { - - AABB mesh_aabb; - - if (multimesh->mesh.is_valid()) { - mesh_aabb = mesh_get_aabb(multimesh->mesh, RID()); - } else { - mesh_aabb.size += Vector3(0.001, 0.001, 0.001); - } - - int stride = multimesh->color_floats + multimesh->xform_floats + multimesh->custom_data_floats; - int count = multimesh->data.size(); - float *data = multimesh->data.ptrw(); - - AABB aabb; - - if (multimesh->transform_format == VS::MULTIMESH_TRANSFORM_2D) { - - for (int i = 0; i < count; i += stride) { - - float *dataptr = &data[i]; - Transform xform; - xform.basis[0][0] = dataptr[0]; - xform.basis[0][1] = dataptr[1]; - xform.origin[0] = dataptr[3]; - xform.basis[1][0] = dataptr[4]; - xform.basis[1][1] = dataptr[5]; - xform.origin[1] = dataptr[7]; - - AABB laabb = xform.xform(mesh_aabb); - if (i == 0) - aabb = laabb; - else - aabb.merge_with(laabb); - } - } else { - - for (int i = 0; i < count; i += stride) { - - float *dataptr = &data[i]; - Transform xform; - - xform.basis.elements[0][0] = dataptr[0]; - xform.basis.elements[0][1] = dataptr[1]; - xform.basis.elements[0][2] = dataptr[2]; - xform.origin.x = dataptr[3]; - xform.basis.elements[1][0] = dataptr[4]; - xform.basis.elements[1][1] = dataptr[5]; - xform.basis.elements[1][2] = dataptr[6]; - xform.origin.y = dataptr[7]; - xform.basis.elements[2][0] = dataptr[8]; - xform.basis.elements[2][1] = dataptr[9]; - xform.basis.elements[2][2] = dataptr[10]; - xform.origin.z = dataptr[11]; - - AABB laabb = xform.xform(mesh_aabb); - if (i == 0) - aabb = laabb; - else - aabb.merge_with(laabb); - } - } - - multimesh->aabb = aabb; - } - multimesh->dirty_aabb = false; - multimesh->dirty_data = false; - - multimesh->instance_change_notify(true, false); - - multimesh_update_list.remove(multimesh_update_list.first()); - } -} - -/* IMMEDIATE API */ - -RID RasterizerStorageGLES3::immediate_create() { - - Immediate *im = memnew(Immediate); - return immediate_owner.make_rid(im); -} - -void RasterizerStorageGLES3::immediate_begin(RID p_immediate, VS::PrimitiveType p_primitive, RID p_texture) { - - ERR_FAIL_INDEX(p_primitive, (int)VS::PRIMITIVE_MAX); - Immediate *im = immediate_owner.get(p_immediate); - ERR_FAIL_COND(!im); - ERR_FAIL_COND(im->building); - - Immediate::Chunk ic; - ic.texture = p_texture; - ic.primitive = p_primitive; - im->chunks.push_back(ic); - im->mask = 0; - im->building = true; -} -void RasterizerStorageGLES3::immediate_vertex(RID p_immediate, const Vector3 &p_vertex) { - - Immediate *im = immediate_owner.get(p_immediate); - ERR_FAIL_COND(!im); - ERR_FAIL_COND(!im->building); - - Immediate::Chunk *c = &im->chunks.back()->get(); - - if (c->vertices.empty() && im->chunks.size() == 1) { - - im->aabb.position = p_vertex; - im->aabb.size = Vector3(); - } else { - im->aabb.expand_to(p_vertex); - } - - if (im->mask & VS::ARRAY_FORMAT_NORMAL) - c->normals.push_back(chunk_normal); - if (im->mask & VS::ARRAY_FORMAT_TANGENT) - c->tangents.push_back(chunk_tangent); - if (im->mask & VS::ARRAY_FORMAT_COLOR) - c->colors.push_back(chunk_color); - if (im->mask & VS::ARRAY_FORMAT_TEX_UV) - c->uvs.push_back(chunk_uv); - if (im->mask & VS::ARRAY_FORMAT_TEX_UV2) - c->uvs2.push_back(chunk_uv2); - im->mask |= VS::ARRAY_FORMAT_VERTEX; - c->vertices.push_back(p_vertex); -} - -void RasterizerStorageGLES3::immediate_normal(RID p_immediate, const Vector3 &p_normal) { - - Immediate *im = immediate_owner.get(p_immediate); - ERR_FAIL_COND(!im); - ERR_FAIL_COND(!im->building); - - im->mask |= VS::ARRAY_FORMAT_NORMAL; - chunk_normal = p_normal; -} -void RasterizerStorageGLES3::immediate_tangent(RID p_immediate, const Plane &p_tangent) { - - Immediate *im = immediate_owner.get(p_immediate); - ERR_FAIL_COND(!im); - ERR_FAIL_COND(!im->building); - - im->mask |= VS::ARRAY_FORMAT_TANGENT; - chunk_tangent = p_tangent; -} -void RasterizerStorageGLES3::immediate_color(RID p_immediate, const Color &p_color) { - - Immediate *im = immediate_owner.get(p_immediate); - ERR_FAIL_COND(!im); - ERR_FAIL_COND(!im->building); - - im->mask |= VS::ARRAY_FORMAT_COLOR; - chunk_color = p_color; -} -void RasterizerStorageGLES3::immediate_uv(RID p_immediate, const Vector2 &tex_uv) { - - Immediate *im = immediate_owner.get(p_immediate); - ERR_FAIL_COND(!im); - ERR_FAIL_COND(!im->building); - - im->mask |= VS::ARRAY_FORMAT_TEX_UV; - chunk_uv = tex_uv; -} -void RasterizerStorageGLES3::immediate_uv2(RID p_immediate, const Vector2 &tex_uv) { - - Immediate *im = immediate_owner.get(p_immediate); - ERR_FAIL_COND(!im); - ERR_FAIL_COND(!im->building); - - im->mask |= VS::ARRAY_FORMAT_TEX_UV2; - chunk_uv2 = tex_uv; -} - -void RasterizerStorageGLES3::immediate_end(RID p_immediate) { - - Immediate *im = immediate_owner.get(p_immediate); - ERR_FAIL_COND(!im); - ERR_FAIL_COND(!im->building); - - im->building = false; - - im->instance_change_notify(true, false); -} -void RasterizerStorageGLES3::immediate_clear(RID p_immediate) { - - Immediate *im = immediate_owner.get(p_immediate); - ERR_FAIL_COND(!im); - ERR_FAIL_COND(im->building); - - im->chunks.clear(); - im->instance_change_notify(true, false); -} - -AABB RasterizerStorageGLES3::immediate_get_aabb(RID p_immediate) const { - - Immediate *im = immediate_owner.get(p_immediate); - ERR_FAIL_COND_V(!im, AABB()); - return im->aabb; -} - -void RasterizerStorageGLES3::immediate_set_material(RID p_immediate, RID p_material) { - - Immediate *im = immediate_owner.get(p_immediate); - ERR_FAIL_COND(!im); - im->material = p_material; - im->instance_change_notify(false, true); -} - -RID RasterizerStorageGLES3::immediate_get_material(RID p_immediate) const { - - const Immediate *im = immediate_owner.get(p_immediate); - ERR_FAIL_COND_V(!im, RID()); - return im->material; -} - -/* SKELETON API */ - -RID RasterizerStorageGLES3::skeleton_create() { - - Skeleton *skeleton = memnew(Skeleton); - - glGenTextures(1, &skeleton->texture); - - return skeleton_owner.make_rid(skeleton); -} - -void RasterizerStorageGLES3::skeleton_allocate(RID p_skeleton, int p_bones, bool p_2d_skeleton) { - - Skeleton *skeleton = skeleton_owner.getornull(p_skeleton); - ERR_FAIL_COND(!skeleton); - ERR_FAIL_COND(p_bones < 0); - - if (skeleton->size == p_bones && skeleton->use_2d == p_2d_skeleton) - return; - - skeleton->size = p_bones; - skeleton->use_2d = p_2d_skeleton; - - int height = p_bones / 256; - if (p_bones % 256) - height++; - - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, skeleton->texture); - - if (skeleton->use_2d) { - skeleton->skel_texture.resize(256 * height * 2 * 4); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, 256, height * 2, 0, GL_RGBA, GL_FLOAT, NULL); - } else { - skeleton->skel_texture.resize(256 * height * 3 * 4); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, 256, height * 3, 0, GL_RGBA, GL_FLOAT, NULL); - } - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - if (!skeleton->update_list.in_list()) { - skeleton_update_list.add(&skeleton->update_list); - } -} -int RasterizerStorageGLES3::skeleton_get_bone_count(RID p_skeleton) const { - - Skeleton *skeleton = skeleton_owner.getornull(p_skeleton); - ERR_FAIL_COND_V(!skeleton, 0); - - return skeleton->size; -} - -void RasterizerStorageGLES3::skeleton_bone_set_transform(RID p_skeleton, int p_bone, const Transform &p_transform) { - - Skeleton *skeleton = skeleton_owner.getornull(p_skeleton); - - ERR_FAIL_COND(!skeleton); - ERR_FAIL_INDEX(p_bone, skeleton->size); - ERR_FAIL_COND(skeleton->use_2d); - - float *texture = skeleton->skel_texture.ptrw(); - - int base_ofs = ((p_bone / 256) * 256) * 3 * 4 + (p_bone % 256) * 4; - - texture[base_ofs + 0] = p_transform.basis[0].x; - texture[base_ofs + 1] = p_transform.basis[0].y; - texture[base_ofs + 2] = p_transform.basis[0].z; - texture[base_ofs + 3] = p_transform.origin.x; - base_ofs += 256 * 4; - texture[base_ofs + 0] = p_transform.basis[1].x; - texture[base_ofs + 1] = p_transform.basis[1].y; - texture[base_ofs + 2] = p_transform.basis[1].z; - texture[base_ofs + 3] = p_transform.origin.y; - base_ofs += 256 * 4; - texture[base_ofs + 0] = p_transform.basis[2].x; - texture[base_ofs + 1] = p_transform.basis[2].y; - texture[base_ofs + 2] = p_transform.basis[2].z; - texture[base_ofs + 3] = p_transform.origin.z; - - if (!skeleton->update_list.in_list()) { - skeleton_update_list.add(&skeleton->update_list); - } -} - -Transform RasterizerStorageGLES3::skeleton_bone_get_transform(RID p_skeleton, int p_bone) const { - - Skeleton *skeleton = skeleton_owner.getornull(p_skeleton); - - ERR_FAIL_COND_V(!skeleton, Transform()); - ERR_FAIL_INDEX_V(p_bone, skeleton->size, Transform()); - ERR_FAIL_COND_V(skeleton->use_2d, Transform()); - - const float *texture = skeleton->skel_texture.ptr(); - - Transform ret; - - int base_ofs = ((p_bone / 256) * 256) * 3 * 4 + (p_bone % 256) * 4; - - ret.basis[0].x = texture[base_ofs + 0]; - ret.basis[0].y = texture[base_ofs + 1]; - ret.basis[0].z = texture[base_ofs + 2]; - ret.origin.x = texture[base_ofs + 3]; - base_ofs += 256 * 4; - ret.basis[1].x = texture[base_ofs + 0]; - ret.basis[1].y = texture[base_ofs + 1]; - ret.basis[1].z = texture[base_ofs + 2]; - ret.origin.y = texture[base_ofs + 3]; - base_ofs += 256 * 4; - ret.basis[2].x = texture[base_ofs + 0]; - ret.basis[2].y = texture[base_ofs + 1]; - ret.basis[2].z = texture[base_ofs + 2]; - ret.origin.z = texture[base_ofs + 3]; - - return ret; -} -void RasterizerStorageGLES3::skeleton_bone_set_transform_2d(RID p_skeleton, int p_bone, const Transform2D &p_transform) { - - Skeleton *skeleton = skeleton_owner.getornull(p_skeleton); - - ERR_FAIL_COND(!skeleton); - ERR_FAIL_INDEX(p_bone, skeleton->size); - ERR_FAIL_COND(!skeleton->use_2d); - - float *texture = skeleton->skel_texture.ptrw(); - - int base_ofs = ((p_bone / 256) * 256) * 2 * 4 + (p_bone % 256) * 4; - - texture[base_ofs + 0] = p_transform[0][0]; - texture[base_ofs + 1] = p_transform[1][0]; - texture[base_ofs + 2] = 0; - texture[base_ofs + 3] = p_transform[2][0]; - base_ofs += 256 * 4; - texture[base_ofs + 0] = p_transform[0][1]; - texture[base_ofs + 1] = p_transform[1][1]; - texture[base_ofs + 2] = 0; - texture[base_ofs + 3] = p_transform[2][1]; - - if (!skeleton->update_list.in_list()) { - skeleton_update_list.add(&skeleton->update_list); - } -} -Transform2D RasterizerStorageGLES3::skeleton_bone_get_transform_2d(RID p_skeleton, int p_bone) const { - - Skeleton *skeleton = skeleton_owner.getornull(p_skeleton); - - ERR_FAIL_COND_V(!skeleton, Transform2D()); - ERR_FAIL_INDEX_V(p_bone, skeleton->size, Transform2D()); - ERR_FAIL_COND_V(!skeleton->use_2d, Transform2D()); - - const float *texture = skeleton->skel_texture.ptr(); - - Transform2D ret; - - int base_ofs = ((p_bone / 256) * 256) * 2 * 4 + (p_bone % 256) * 4; - - ret[0][0] = texture[base_ofs + 0]; - ret[1][0] = texture[base_ofs + 1]; - ret[2][0] = texture[base_ofs + 3]; - base_ofs += 256 * 4; - ret[0][1] = texture[base_ofs + 0]; - ret[1][1] = texture[base_ofs + 1]; - ret[2][1] = texture[base_ofs + 3]; - - return ret; -} - -void RasterizerStorageGLES3::skeleton_set_base_transform_2d(RID p_skeleton, const Transform2D &p_base_transform) { - - Skeleton *skeleton = skeleton_owner.getornull(p_skeleton); - - ERR_FAIL_COND(!skeleton->use_2d); - - skeleton->base_transform_2d = p_base_transform; -} - -void RasterizerStorageGLES3::update_dirty_skeletons() { - - glActiveTexture(GL_TEXTURE0); - - while (skeleton_update_list.first()) { - - Skeleton *skeleton = skeleton_update_list.first()->self(); - if (skeleton->size) { - - int height = skeleton->size / 256; - if (skeleton->size % 256) - height++; - - glBindTexture(GL_TEXTURE_2D, skeleton->texture); - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 256, height * (skeleton->use_2d ? 2 : 3), GL_RGBA, GL_FLOAT, skeleton->skel_texture.ptr()); - } - - for (Set<RasterizerScene::InstanceBase *>::Element *E = skeleton->instances.front(); E; E = E->next()) { - E->get()->base_changed(true, false); - } - - skeleton_update_list.remove(skeleton_update_list.first()); - } -} - -/* Light API */ - -RID RasterizerStorageGLES3::light_create(VS::LightType p_type) { - - Light *light = memnew(Light); - light->type = p_type; - - light->param[VS::LIGHT_PARAM_ENERGY] = 1.0; - light->param[VS::LIGHT_PARAM_INDIRECT_ENERGY] = 1.0; - light->param[VS::LIGHT_PARAM_SPECULAR] = 0.5; - light->param[VS::LIGHT_PARAM_RANGE] = 1.0; - light->param[VS::LIGHT_PARAM_SPOT_ANGLE] = 45; - light->param[VS::LIGHT_PARAM_CONTACT_SHADOW_SIZE] = 45; - light->param[VS::LIGHT_PARAM_SHADOW_MAX_DISTANCE] = 0; - light->param[VS::LIGHT_PARAM_SHADOW_SPLIT_1_OFFSET] = 0.1; - light->param[VS::LIGHT_PARAM_SHADOW_SPLIT_2_OFFSET] = 0.3; - light->param[VS::LIGHT_PARAM_SHADOW_SPLIT_3_OFFSET] = 0.6; - light->param[VS::LIGHT_PARAM_SHADOW_NORMAL_BIAS] = 0.1; - light->param[VS::LIGHT_PARAM_SHADOW_BIAS_SPLIT_SCALE] = 0.1; - - light->color = Color(1, 1, 1, 1); - light->shadow = false; - light->negative = false; - light->cull_mask = 0xFFFFFFFF; - light->directional_shadow_mode = VS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL; - light->omni_shadow_mode = VS::LIGHT_OMNI_SHADOW_DUAL_PARABOLOID; - light->omni_shadow_detail = VS::LIGHT_OMNI_SHADOW_DETAIL_VERTICAL; - light->directional_blend_splits = false; - light->directional_range_mode = VS::LIGHT_DIRECTIONAL_SHADOW_DEPTH_RANGE_STABLE; - light->reverse_cull = false; - light->use_gi = true; - light->version = 0; - - return light_owner.make_rid(light); -} - -void RasterizerStorageGLES3::light_set_color(RID p_light, const Color &p_color) { - - Light *light = light_owner.getornull(p_light); - ERR_FAIL_COND(!light); - - light->color = p_color; -} -void RasterizerStorageGLES3::light_set_param(RID p_light, VS::LightParam p_param, float p_value) { - - Light *light = light_owner.getornull(p_light); - ERR_FAIL_COND(!light); - ERR_FAIL_INDEX(p_param, VS::LIGHT_PARAM_MAX); - - switch (p_param) { - case VS::LIGHT_PARAM_RANGE: - case VS::LIGHT_PARAM_SPOT_ANGLE: - case VS::LIGHT_PARAM_SHADOW_MAX_DISTANCE: - case VS::LIGHT_PARAM_SHADOW_SPLIT_1_OFFSET: - case VS::LIGHT_PARAM_SHADOW_SPLIT_2_OFFSET: - case VS::LIGHT_PARAM_SHADOW_SPLIT_3_OFFSET: - case VS::LIGHT_PARAM_SHADOW_NORMAL_BIAS: - case VS::LIGHT_PARAM_SHADOW_BIAS: { - - light->version++; - light->instance_change_notify(true, false); - } break; - default: { - } - } - - light->param[p_param] = p_value; -} -void RasterizerStorageGLES3::light_set_shadow(RID p_light, bool p_enabled) { - - Light *light = light_owner.getornull(p_light); - ERR_FAIL_COND(!light); - light->shadow = p_enabled; - - light->version++; - light->instance_change_notify(true, false); -} - -void RasterizerStorageGLES3::light_set_shadow_color(RID p_light, const Color &p_color) { - - Light *light = light_owner.getornull(p_light); - ERR_FAIL_COND(!light); - light->shadow_color = p_color; -} - -void RasterizerStorageGLES3::light_set_projector(RID p_light, RID p_texture) { - - Light *light = light_owner.getornull(p_light); - ERR_FAIL_COND(!light); - - light->projector = p_texture; -} - -void RasterizerStorageGLES3::light_set_negative(RID p_light, bool p_enable) { - - Light *light = light_owner.getornull(p_light); - ERR_FAIL_COND(!light); - - light->negative = p_enable; -} -void RasterizerStorageGLES3::light_set_cull_mask(RID p_light, uint32_t p_mask) { - - Light *light = light_owner.getornull(p_light); - ERR_FAIL_COND(!light); - - light->cull_mask = p_mask; - - light->version++; - light->instance_change_notify(true, false); -} - -void RasterizerStorageGLES3::light_set_reverse_cull_face_mode(RID p_light, bool p_enabled) { - - Light *light = light_owner.getornull(p_light); - ERR_FAIL_COND(!light); - - light->reverse_cull = p_enabled; - - light->version++; - light->instance_change_notify(true, false); -} - -void RasterizerStorageGLES3::light_set_use_gi(RID p_light, bool p_enabled) { - Light *light = light_owner.getornull(p_light); - ERR_FAIL_COND(!light); - - light->use_gi = p_enabled; - - light->version++; - light->instance_change_notify(true, false); -} -void RasterizerStorageGLES3::light_omni_set_shadow_mode(RID p_light, VS::LightOmniShadowMode p_mode) { - - Light *light = light_owner.getornull(p_light); - ERR_FAIL_COND(!light); - - light->omni_shadow_mode = p_mode; - - light->version++; - light->instance_change_notify(true, false); -} - -VS::LightOmniShadowMode RasterizerStorageGLES3::light_omni_get_shadow_mode(RID p_light) { - - const Light *light = light_owner.getornull(p_light); - ERR_FAIL_COND_V(!light, VS::LIGHT_OMNI_SHADOW_CUBE); - - return light->omni_shadow_mode; -} - -void RasterizerStorageGLES3::light_omni_set_shadow_detail(RID p_light, VS::LightOmniShadowDetail p_detail) { - - Light *light = light_owner.getornull(p_light); - ERR_FAIL_COND(!light); - - light->omni_shadow_detail = p_detail; - light->version++; - light->instance_change_notify(true, false); -} - -void RasterizerStorageGLES3::light_directional_set_shadow_mode(RID p_light, VS::LightDirectionalShadowMode p_mode) { - - Light *light = light_owner.getornull(p_light); - ERR_FAIL_COND(!light); - - light->directional_shadow_mode = p_mode; - light->version++; - light->instance_change_notify(true, false); -} - -void RasterizerStorageGLES3::light_directional_set_blend_splits(RID p_light, bool p_enable) { - - Light *light = light_owner.getornull(p_light); - ERR_FAIL_COND(!light); - - light->directional_blend_splits = p_enable; - light->version++; - light->instance_change_notify(true, false); -} - -bool RasterizerStorageGLES3::light_directional_get_blend_splits(RID p_light) const { - - const Light *light = light_owner.getornull(p_light); - ERR_FAIL_COND_V(!light, false); - - return light->directional_blend_splits; -} - -VS::LightDirectionalShadowMode RasterizerStorageGLES3::light_directional_get_shadow_mode(RID p_light) { - - const Light *light = light_owner.getornull(p_light); - ERR_FAIL_COND_V(!light, VS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL); - - return light->directional_shadow_mode; -} - -void RasterizerStorageGLES3::light_directional_set_shadow_depth_range_mode(RID p_light, VS::LightDirectionalShadowDepthRangeMode p_range_mode) { - - Light *light = light_owner.getornull(p_light); - ERR_FAIL_COND(!light); - - light->directional_range_mode = p_range_mode; -} - -VS::LightDirectionalShadowDepthRangeMode RasterizerStorageGLES3::light_directional_get_shadow_depth_range_mode(RID p_light) const { - - const Light *light = light_owner.getornull(p_light); - ERR_FAIL_COND_V(!light, VS::LIGHT_DIRECTIONAL_SHADOW_DEPTH_RANGE_STABLE); - - return light->directional_range_mode; -} - -VS::LightType RasterizerStorageGLES3::light_get_type(RID p_light) const { - - const Light *light = light_owner.getornull(p_light); - ERR_FAIL_COND_V(!light, VS::LIGHT_DIRECTIONAL); - - return light->type; -} - -float RasterizerStorageGLES3::light_get_param(RID p_light, VS::LightParam p_param) { - - const Light *light = light_owner.getornull(p_light); - ERR_FAIL_COND_V(!light, VS::LIGHT_DIRECTIONAL); - - return light->param[p_param]; -} - -Color RasterizerStorageGLES3::light_get_color(RID p_light) { - - const Light *light = light_owner.getornull(p_light); - ERR_FAIL_COND_V(!light, Color()); - - return light->color; -} - -bool RasterizerStorageGLES3::light_get_use_gi(RID p_light) { - Light *light = light_owner.getornull(p_light); - ERR_FAIL_COND_V(!light, false); - - return light->use_gi; -} - -bool RasterizerStorageGLES3::light_has_shadow(RID p_light) const { - - const Light *light = light_owner.getornull(p_light); - ERR_FAIL_COND_V(!light, VS::LIGHT_DIRECTIONAL); - - return light->shadow; -} - -uint64_t RasterizerStorageGLES3::light_get_version(RID p_light) const { - - const Light *light = light_owner.getornull(p_light); - ERR_FAIL_COND_V(!light, 0); - - return light->version; -} - -AABB RasterizerStorageGLES3::light_get_aabb(RID p_light) const { - - const Light *light = light_owner.getornull(p_light); - ERR_FAIL_COND_V(!light, AABB()); - - switch (light->type) { - - case VS::LIGHT_SPOT: { - - float len = light->param[VS::LIGHT_PARAM_RANGE]; - float size = Math::tan(Math::deg2rad(light->param[VS::LIGHT_PARAM_SPOT_ANGLE])) * len; - return AABB(Vector3(-size, -size, -len), Vector3(size * 2, size * 2, len)); - }; - case VS::LIGHT_OMNI: { - - float r = light->param[VS::LIGHT_PARAM_RANGE]; - return AABB(-Vector3(r, r, r), Vector3(r, r, r) * 2); - }; - case VS::LIGHT_DIRECTIONAL: { - - return AABB(); - }; - } - - ERR_FAIL_V(AABB()); -} - -/* PROBE API */ - -RID RasterizerStorageGLES3::reflection_probe_create() { - - ReflectionProbe *reflection_probe = memnew(ReflectionProbe); - - reflection_probe->intensity = 1.0; - reflection_probe->interior_ambient = Color(); - reflection_probe->interior_ambient_energy = 1.0; - reflection_probe->interior_ambient_probe_contrib = 0.0; - - reflection_probe->max_distance = 0; - reflection_probe->extents = Vector3(1, 1, 1); - reflection_probe->origin_offset = Vector3(0, 0, 0); - reflection_probe->interior = false; - reflection_probe->box_projection = false; - reflection_probe->enable_shadows = false; - reflection_probe->cull_mask = (1 << 20) - 1; - reflection_probe->update_mode = VS::REFLECTION_PROBE_UPDATE_ONCE; - - return reflection_probe_owner.make_rid(reflection_probe); -} - -void RasterizerStorageGLES3::reflection_probe_set_update_mode(RID p_probe, VS::ReflectionProbeUpdateMode p_mode) { - - ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); - ERR_FAIL_COND(!reflection_probe); - - reflection_probe->update_mode = p_mode; - reflection_probe->instance_change_notify(true, false); -} - -void RasterizerStorageGLES3::reflection_probe_set_intensity(RID p_probe, float p_intensity) { - - ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); - ERR_FAIL_COND(!reflection_probe); - - reflection_probe->intensity = p_intensity; -} - -void RasterizerStorageGLES3::reflection_probe_set_interior_ambient(RID p_probe, const Color &p_ambient) { - - ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); - ERR_FAIL_COND(!reflection_probe); - - reflection_probe->interior_ambient = p_ambient; -} - -void RasterizerStorageGLES3::reflection_probe_set_interior_ambient_energy(RID p_probe, float p_energy) { - - ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); - ERR_FAIL_COND(!reflection_probe); - - reflection_probe->interior_ambient_energy = p_energy; -} - -void RasterizerStorageGLES3::reflection_probe_set_interior_ambient_probe_contribution(RID p_probe, float p_contrib) { - - ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); - ERR_FAIL_COND(!reflection_probe); - - reflection_probe->interior_ambient_probe_contrib = p_contrib; -} - -void RasterizerStorageGLES3::reflection_probe_set_max_distance(RID p_probe, float p_distance) { - - ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); - ERR_FAIL_COND(!reflection_probe); - - reflection_probe->max_distance = p_distance; - reflection_probe->instance_change_notify(true, false); -} -void RasterizerStorageGLES3::reflection_probe_set_extents(RID p_probe, const Vector3 &p_extents) { - - ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); - ERR_FAIL_COND(!reflection_probe); - - reflection_probe->extents = p_extents; - reflection_probe->instance_change_notify(true, false); -} -void RasterizerStorageGLES3::reflection_probe_set_origin_offset(RID p_probe, const Vector3 &p_offset) { - - ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); - ERR_FAIL_COND(!reflection_probe); - - reflection_probe->origin_offset = p_offset; - reflection_probe->instance_change_notify(true, false); -} - -void RasterizerStorageGLES3::reflection_probe_set_as_interior(RID p_probe, bool p_enable) { - - ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); - ERR_FAIL_COND(!reflection_probe); - - reflection_probe->interior = p_enable; - reflection_probe->instance_change_notify(true, false); -} -void RasterizerStorageGLES3::reflection_probe_set_enable_box_projection(RID p_probe, bool p_enable) { - - ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); - ERR_FAIL_COND(!reflection_probe); - - reflection_probe->box_projection = p_enable; -} - -void RasterizerStorageGLES3::reflection_probe_set_enable_shadows(RID p_probe, bool p_enable) { - - ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); - ERR_FAIL_COND(!reflection_probe); - - reflection_probe->enable_shadows = p_enable; - reflection_probe->instance_change_notify(true, false); -} -void RasterizerStorageGLES3::reflection_probe_set_cull_mask(RID p_probe, uint32_t p_layers) { - - ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); - ERR_FAIL_COND(!reflection_probe); - - reflection_probe->cull_mask = p_layers; - reflection_probe->instance_change_notify(true, false); -} - -void RasterizerStorageGLES3::reflection_probe_set_resolution(RID p_probe, int p_resolution) { -} - -AABB RasterizerStorageGLES3::reflection_probe_get_aabb(RID p_probe) const { - const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); - ERR_FAIL_COND_V(!reflection_probe, AABB()); - - AABB aabb; - aabb.position = -reflection_probe->extents; - aabb.size = reflection_probe->extents * 2.0; - - return aabb; -} -VS::ReflectionProbeUpdateMode RasterizerStorageGLES3::reflection_probe_get_update_mode(RID p_probe) const { - - const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); - ERR_FAIL_COND_V(!reflection_probe, VS::REFLECTION_PROBE_UPDATE_ALWAYS); - - return reflection_probe->update_mode; -} - -uint32_t RasterizerStorageGLES3::reflection_probe_get_cull_mask(RID p_probe) const { - - const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); - ERR_FAIL_COND_V(!reflection_probe, 0); - - return reflection_probe->cull_mask; -} - -Vector3 RasterizerStorageGLES3::reflection_probe_get_extents(RID p_probe) const { - - const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); - ERR_FAIL_COND_V(!reflection_probe, Vector3()); - - return reflection_probe->extents; -} -Vector3 RasterizerStorageGLES3::reflection_probe_get_origin_offset(RID p_probe) const { - - const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); - ERR_FAIL_COND_V(!reflection_probe, Vector3()); - - return reflection_probe->origin_offset; -} - -bool RasterizerStorageGLES3::reflection_probe_renders_shadows(RID p_probe) const { - - const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); - ERR_FAIL_COND_V(!reflection_probe, false); - - return reflection_probe->enable_shadows; -} - -float RasterizerStorageGLES3::reflection_probe_get_origin_max_distance(RID p_probe) const { - - const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); - ERR_FAIL_COND_V(!reflection_probe, 0); - - return reflection_probe->max_distance; -} - -RID RasterizerStorageGLES3::gi_probe_create() { - - GIProbe *gip = memnew(GIProbe); - - gip->bounds = AABB(Vector3(), Vector3(1, 1, 1)); - gip->dynamic_range = 1.0; - gip->energy = 1.0; - gip->propagation = 1.0; - gip->bias = 0.4; - gip->normal_bias = 0.4; - gip->interior = false; - gip->compress = false; - gip->version = 1; - gip->cell_size = 1.0; - - return gi_probe_owner.make_rid(gip); -} - -void RasterizerStorageGLES3::gi_probe_set_bounds(RID p_probe, const AABB &p_bounds) { - - GIProbe *gip = gi_probe_owner.getornull(p_probe); - ERR_FAIL_COND(!gip); - - gip->bounds = p_bounds; - gip->version++; - gip->instance_change_notify(true, false); -} -AABB RasterizerStorageGLES3::gi_probe_get_bounds(RID p_probe) const { - - const GIProbe *gip = gi_probe_owner.getornull(p_probe); - ERR_FAIL_COND_V(!gip, AABB()); - - return gip->bounds; -} - -void RasterizerStorageGLES3::gi_probe_set_cell_size(RID p_probe, float p_size) { - - GIProbe *gip = gi_probe_owner.getornull(p_probe); - ERR_FAIL_COND(!gip); - - gip->cell_size = p_size; - gip->version++; - gip->instance_change_notify(true, false); -} - -float RasterizerStorageGLES3::gi_probe_get_cell_size(RID p_probe) const { - - const GIProbe *gip = gi_probe_owner.getornull(p_probe); - ERR_FAIL_COND_V(!gip, 0); - - return gip->cell_size; -} - -void RasterizerStorageGLES3::gi_probe_set_to_cell_xform(RID p_probe, const Transform &p_xform) { - - GIProbe *gip = gi_probe_owner.getornull(p_probe); - ERR_FAIL_COND(!gip); - - gip->to_cell = p_xform; -} - -Transform RasterizerStorageGLES3::gi_probe_get_to_cell_xform(RID p_probe) const { - - const GIProbe *gip = gi_probe_owner.getornull(p_probe); - ERR_FAIL_COND_V(!gip, Transform()); - - return gip->to_cell; -} - -void RasterizerStorageGLES3::gi_probe_set_dynamic_data(RID p_probe, const PoolVector<int> &p_data) { - GIProbe *gip = gi_probe_owner.getornull(p_probe); - ERR_FAIL_COND(!gip); - - gip->dynamic_data = p_data; - gip->version++; - gip->instance_change_notify(true, false); -} -PoolVector<int> RasterizerStorageGLES3::gi_probe_get_dynamic_data(RID p_probe) const { - - const GIProbe *gip = gi_probe_owner.getornull(p_probe); - ERR_FAIL_COND_V(!gip, PoolVector<int>()); - - return gip->dynamic_data; -} - -void RasterizerStorageGLES3::gi_probe_set_dynamic_range(RID p_probe, int p_range) { - - GIProbe *gip = gi_probe_owner.getornull(p_probe); - ERR_FAIL_COND(!gip); - - gip->dynamic_range = p_range; -} -int RasterizerStorageGLES3::gi_probe_get_dynamic_range(RID p_probe) const { - - const GIProbe *gip = gi_probe_owner.getornull(p_probe); - ERR_FAIL_COND_V(!gip, 0); - - return gip->dynamic_range; -} - -void RasterizerStorageGLES3::gi_probe_set_energy(RID p_probe, float p_range) { - - GIProbe *gip = gi_probe_owner.getornull(p_probe); - ERR_FAIL_COND(!gip); - - gip->energy = p_range; -} - -void RasterizerStorageGLES3::gi_probe_set_bias(RID p_probe, float p_range) { - - GIProbe *gip = gi_probe_owner.getornull(p_probe); - ERR_FAIL_COND(!gip); - - gip->bias = p_range; -} - -void RasterizerStorageGLES3::gi_probe_set_normal_bias(RID p_probe, float p_range) { - - GIProbe *gip = gi_probe_owner.getornull(p_probe); - ERR_FAIL_COND(!gip); - - gip->normal_bias = p_range; -} - -void RasterizerStorageGLES3::gi_probe_set_propagation(RID p_probe, float p_range) { - - GIProbe *gip = gi_probe_owner.getornull(p_probe); - ERR_FAIL_COND(!gip); - - gip->propagation = p_range; -} - -void RasterizerStorageGLES3::gi_probe_set_interior(RID p_probe, bool p_enable) { - - GIProbe *gip = gi_probe_owner.getornull(p_probe); - ERR_FAIL_COND(!gip); - - gip->interior = p_enable; -} - -bool RasterizerStorageGLES3::gi_probe_is_interior(RID p_probe) const { - - const GIProbe *gip = gi_probe_owner.getornull(p_probe); - ERR_FAIL_COND_V(!gip, false); - - return gip->interior; -} - -void RasterizerStorageGLES3::gi_probe_set_compress(RID p_probe, bool p_enable) { - - GIProbe *gip = gi_probe_owner.getornull(p_probe); - ERR_FAIL_COND(!gip); - - gip->compress = p_enable; -} - -bool RasterizerStorageGLES3::gi_probe_is_compressed(RID p_probe) const { - - const GIProbe *gip = gi_probe_owner.getornull(p_probe); - ERR_FAIL_COND_V(!gip, false); - - return gip->compress; -} -float RasterizerStorageGLES3::gi_probe_get_energy(RID p_probe) const { - - const GIProbe *gip = gi_probe_owner.getornull(p_probe); - ERR_FAIL_COND_V(!gip, 0); - - return gip->energy; -} - -float RasterizerStorageGLES3::gi_probe_get_bias(RID p_probe) const { - - const GIProbe *gip = gi_probe_owner.getornull(p_probe); - ERR_FAIL_COND_V(!gip, 0); - - return gip->bias; -} - -float RasterizerStorageGLES3::gi_probe_get_normal_bias(RID p_probe) const { - - const GIProbe *gip = gi_probe_owner.getornull(p_probe); - ERR_FAIL_COND_V(!gip, 0); - - return gip->normal_bias; -} - -float RasterizerStorageGLES3::gi_probe_get_propagation(RID p_probe) const { - - const GIProbe *gip = gi_probe_owner.getornull(p_probe); - ERR_FAIL_COND_V(!gip, 0); - - return gip->propagation; -} - -uint32_t RasterizerStorageGLES3::gi_probe_get_version(RID p_probe) { - - const GIProbe *gip = gi_probe_owner.getornull(p_probe); - ERR_FAIL_COND_V(!gip, 0); - - return gip->version; -} - -RasterizerStorage::GIProbeCompression RasterizerStorageGLES3::gi_probe_get_dynamic_data_get_preferred_compression() const { - if (config.s3tc_supported) { - return GI_PROBE_S3TC; - } else { - return GI_PROBE_UNCOMPRESSED; - } -} - -RID RasterizerStorageGLES3::gi_probe_dynamic_data_create(int p_width, int p_height, int p_depth, GIProbeCompression p_compression) { - - GIProbeData *gipd = memnew(GIProbeData); - - gipd->width = p_width; - gipd->height = p_height; - gipd->depth = p_depth; - gipd->compression = p_compression; - - glActiveTexture(GL_TEXTURE0); - glGenTextures(1, &gipd->tex_id); - glBindTexture(GL_TEXTURE_3D, gipd->tex_id); - - int level = 0; - int min_size = 1; - - if (gipd->compression == GI_PROBE_S3TC) { - min_size = 4; - } - - while (true) { - - if (gipd->compression == GI_PROBE_S3TC) { - int size = p_width * p_height * p_depth; - glCompressedTexImage3D(GL_TEXTURE_3D, level, _EXT_COMPRESSED_RGBA_S3TC_DXT5_EXT, p_width, p_height, p_depth, 0, size, NULL); - } else { - glTexImage3D(GL_TEXTURE_3D, level, GL_RGBA8, p_width, p_height, p_depth, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); - } - - if (p_width <= min_size || p_height <= min_size || p_depth <= min_size) - break; - p_width >>= 1; - p_height >>= 1; - p_depth >>= 1; - level++; - } - - glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_BASE_LEVEL, 0); - glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAX_LEVEL, level); - - gipd->levels = level + 1; - - return gi_probe_data_owner.make_rid(gipd); -} - -void RasterizerStorageGLES3::gi_probe_dynamic_data_update(RID p_gi_probe_data, int p_depth_slice, int p_slice_count, int p_mipmap, const void *p_data) { - - GIProbeData *gipd = gi_probe_data_owner.getornull(p_gi_probe_data); - ERR_FAIL_COND(!gipd); - /* - Vector<uint8_t> data; - data.resize((gipd->width>>p_mipmap)*(gipd->height>>p_mipmap)*(gipd->depth>>p_mipmap)*4); - - for(int i=0;i<(gipd->width>>p_mipmap);i++) { - for(int j=0;j<(gipd->height>>p_mipmap);j++) { - for(int k=0;k<(gipd->depth>>p_mipmap);k++) { - - int ofs = (k*(gipd->height>>p_mipmap)*(gipd->width>>p_mipmap)) + j *(gipd->width>>p_mipmap) + i; - ofs*=4; - data[ofs+0]=i*0xFF/(gipd->width>>p_mipmap); - data[ofs+1]=j*0xFF/(gipd->height>>p_mipmap); - data[ofs+2]=k*0xFF/(gipd->depth>>p_mipmap); - data[ofs+3]=0xFF; - } - } - } -*/ - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_3D, gipd->tex_id); - if (gipd->compression == GI_PROBE_S3TC) { - int size = (gipd->width >> p_mipmap) * (gipd->height >> p_mipmap) * p_slice_count; - glCompressedTexSubImage3D(GL_TEXTURE_3D, p_mipmap, 0, 0, p_depth_slice, gipd->width >> p_mipmap, gipd->height >> p_mipmap, p_slice_count, _EXT_COMPRESSED_RGBA_S3TC_DXT5_EXT, size, p_data); - } else { - glTexSubImage3D(GL_TEXTURE_3D, p_mipmap, 0, 0, p_depth_slice, gipd->width >> p_mipmap, gipd->height >> p_mipmap, p_slice_count, GL_RGBA, GL_UNSIGNED_BYTE, p_data); - } - //glTexImage3D(GL_TEXTURE_3D,p_mipmap,GL_RGBA8,gipd->width>>p_mipmap,gipd->height>>p_mipmap,gipd->depth>>p_mipmap,0,GL_RGBA,GL_UNSIGNED_BYTE,p_data); - //glTexImage3D(GL_TEXTURE_3D,p_mipmap,GL_RGBA8,gipd->width>>p_mipmap,gipd->height>>p_mipmap,gipd->depth>>p_mipmap,0,GL_RGBA,GL_UNSIGNED_BYTE,data.ptr()); -} -///////////////////////////// - -RID RasterizerStorageGLES3::lightmap_capture_create() { - - LightmapCapture *capture = memnew(LightmapCapture); - return lightmap_capture_data_owner.make_rid(capture); -} - -void RasterizerStorageGLES3::lightmap_capture_set_bounds(RID p_capture, const AABB &p_bounds) { - - LightmapCapture *capture = lightmap_capture_data_owner.getornull(p_capture); - ERR_FAIL_COND(!capture); - capture->bounds = p_bounds; - capture->instance_change_notify(true, false); -} -AABB RasterizerStorageGLES3::lightmap_capture_get_bounds(RID p_capture) const { - - const LightmapCapture *capture = lightmap_capture_data_owner.getornull(p_capture); - ERR_FAIL_COND_V(!capture, AABB()); - return capture->bounds; -} -void RasterizerStorageGLES3::lightmap_capture_set_octree(RID p_capture, const PoolVector<uint8_t> &p_octree) { - - LightmapCapture *capture = lightmap_capture_data_owner.getornull(p_capture); - ERR_FAIL_COND(!capture); - - ERR_FAIL_COND(p_octree.size() == 0 || (p_octree.size() % sizeof(LightmapCaptureOctree)) != 0); - - capture->octree.resize(p_octree.size() / sizeof(LightmapCaptureOctree)); - if (p_octree.size()) { - PoolVector<LightmapCaptureOctree>::Write w = capture->octree.write(); - PoolVector<uint8_t>::Read r = p_octree.read(); - copymem(w.ptr(), r.ptr(), p_octree.size()); - } - capture->instance_change_notify(true, false); -} -PoolVector<uint8_t> RasterizerStorageGLES3::lightmap_capture_get_octree(RID p_capture) const { - - const LightmapCapture *capture = lightmap_capture_data_owner.getornull(p_capture); - ERR_FAIL_COND_V(!capture, PoolVector<uint8_t>()); - - if (capture->octree.size() == 0) - return PoolVector<uint8_t>(); - - PoolVector<uint8_t> ret; - ret.resize(capture->octree.size() * sizeof(LightmapCaptureOctree)); - { - PoolVector<LightmapCaptureOctree>::Read r = capture->octree.read(); - PoolVector<uint8_t>::Write w = ret.write(); - copymem(w.ptr(), r.ptr(), ret.size()); - } - - return ret; -} - -void RasterizerStorageGLES3::lightmap_capture_set_octree_cell_transform(RID p_capture, const Transform &p_xform) { - LightmapCapture *capture = lightmap_capture_data_owner.getornull(p_capture); - ERR_FAIL_COND(!capture); - capture->cell_xform = p_xform; -} - -Transform RasterizerStorageGLES3::lightmap_capture_get_octree_cell_transform(RID p_capture) const { - const LightmapCapture *capture = lightmap_capture_data_owner.getornull(p_capture); - ERR_FAIL_COND_V(!capture, Transform()); - return capture->cell_xform; -} - -void RasterizerStorageGLES3::lightmap_capture_set_octree_cell_subdiv(RID p_capture, int p_subdiv) { - LightmapCapture *capture = lightmap_capture_data_owner.getornull(p_capture); - ERR_FAIL_COND(!capture); - capture->cell_subdiv = p_subdiv; -} - -int RasterizerStorageGLES3::lightmap_capture_get_octree_cell_subdiv(RID p_capture) const { - const LightmapCapture *capture = lightmap_capture_data_owner.getornull(p_capture); - ERR_FAIL_COND_V(!capture, 0); - return capture->cell_subdiv; -} - -void RasterizerStorageGLES3::lightmap_capture_set_energy(RID p_capture, float p_energy) { - - LightmapCapture *capture = lightmap_capture_data_owner.getornull(p_capture); - ERR_FAIL_COND(!capture); - capture->energy = p_energy; -} - -float RasterizerStorageGLES3::lightmap_capture_get_energy(RID p_capture) const { - - const LightmapCapture *capture = lightmap_capture_data_owner.getornull(p_capture); - ERR_FAIL_COND_V(!capture, 0); - return capture->energy; -} - -const PoolVector<RasterizerStorage::LightmapCaptureOctree> *RasterizerStorageGLES3::lightmap_capture_get_octree_ptr(RID p_capture) const { - const LightmapCapture *capture = lightmap_capture_data_owner.getornull(p_capture); - ERR_FAIL_COND_V(!capture, NULL); - return &capture->octree; -} - -/////// - -RID RasterizerStorageGLES3::particles_create() { - - Particles *particles = memnew(Particles); - - return particles_owner.make_rid(particles); -} - -void RasterizerStorageGLES3::particles_set_emitting(RID p_particles, bool p_emitting) { - - Particles *particles = particles_owner.getornull(p_particles); - ERR_FAIL_COND(!particles); - - particles->emitting = p_emitting; -} - -bool RasterizerStorageGLES3::particles_get_emitting(RID p_particles) { - Particles *particles = particles_owner.getornull(p_particles); - ERR_FAIL_COND_V(!particles, false); - - return particles->emitting; -} - -void RasterizerStorageGLES3::particles_set_amount(RID p_particles, int p_amount) { - - Particles *particles = particles_owner.getornull(p_particles); - ERR_FAIL_COND(!particles); - - particles->amount = p_amount; - - int floats = p_amount * 24; - float *data = memnew_arr(float, floats); - - for (int i = 0; i < floats; i++) { - data[i] = 0; - } - - for (int i = 0; i < 2; i++) { - - glBindVertexArray(particles->particle_vaos[i]); - - glBindBuffer(GL_ARRAY_BUFFER, particles->particle_buffers[i]); - glBufferData(GL_ARRAY_BUFFER, floats * sizeof(float), data, GL_STATIC_DRAW); - - for (int j = 0; j < 6; j++) { - glEnableVertexAttribArray(j); - glVertexAttribPointer(j, 4, GL_FLOAT, GL_FALSE, sizeof(float) * 4 * 6, CAST_INT_TO_UCHAR_PTR(j * 16)); - } - } - - if (particles->histories_enabled) { - - for (int i = 0; i < 2; i++) { - glBindVertexArray(particles->particle_vao_histories[i]); - - glBindBuffer(GL_ARRAY_BUFFER, particles->particle_buffer_histories[i]); - glBufferData(GL_ARRAY_BUFFER, floats * sizeof(float), data, GL_DYNAMIC_COPY); - - for (int j = 0; j < 6; j++) { - glEnableVertexAttribArray(j); - glVertexAttribPointer(j, 4, GL_FLOAT, GL_FALSE, sizeof(float) * 4 * 6, CAST_INT_TO_UCHAR_PTR(j * 16)); - } - particles->particle_valid_histories[i] = false; - } - } - - glBindVertexArray(0); - - particles->prev_ticks = 0; - particles->phase = 0; - particles->prev_phase = 0; - particles->clear = true; - - memdelete_arr(data); -} - -void RasterizerStorageGLES3::particles_set_lifetime(RID p_particles, float p_lifetime) { - - Particles *particles = particles_owner.getornull(p_particles); - ERR_FAIL_COND(!particles); - particles->lifetime = p_lifetime; -} - -void RasterizerStorageGLES3::particles_set_one_shot(RID p_particles, bool p_one_shot) { - - Particles *particles = particles_owner.getornull(p_particles); - ERR_FAIL_COND(!particles); - particles->one_shot = p_one_shot; -} - -void RasterizerStorageGLES3::particles_set_pre_process_time(RID p_particles, float p_time) { - - Particles *particles = particles_owner.getornull(p_particles); - ERR_FAIL_COND(!particles); - particles->pre_process_time = p_time; -} -void RasterizerStorageGLES3::particles_set_explosiveness_ratio(RID p_particles, float p_ratio) { - - Particles *particles = particles_owner.getornull(p_particles); - ERR_FAIL_COND(!particles); - particles->explosiveness = p_ratio; -} -void RasterizerStorageGLES3::particles_set_randomness_ratio(RID p_particles, float p_ratio) { - - Particles *particles = particles_owner.getornull(p_particles); - ERR_FAIL_COND(!particles); - particles->randomness = p_ratio; -} - -void RasterizerStorageGLES3::_particles_update_histories(Particles *particles) { - - bool needs_histories = particles->draw_order == VS::PARTICLES_DRAW_ORDER_VIEW_DEPTH; - - if (needs_histories == particles->histories_enabled) - return; - - particles->histories_enabled = needs_histories; - - int floats = particles->amount * 24; - - if (!needs_histories) { - - glDeleteBuffers(2, particles->particle_buffer_histories); - glDeleteVertexArrays(2, particles->particle_vao_histories); - - } else { - - glGenBuffers(2, particles->particle_buffer_histories); - glGenVertexArrays(2, particles->particle_vao_histories); - - for (int i = 0; i < 2; i++) { - glBindVertexArray(particles->particle_vao_histories[i]); - - glBindBuffer(GL_ARRAY_BUFFER, particles->particle_buffer_histories[i]); - glBufferData(GL_ARRAY_BUFFER, floats * sizeof(float), NULL, GL_DYNAMIC_COPY); - - for (int j = 0; j < 6; j++) { - glEnableVertexAttribArray(j); - glVertexAttribPointer(j, 4, GL_FLOAT, GL_FALSE, sizeof(float) * 4 * 6, CAST_INT_TO_UCHAR_PTR(j * 16)); - } - - particles->particle_valid_histories[i] = false; - } - } - - particles->clear = true; -} - -void RasterizerStorageGLES3::particles_set_custom_aabb(RID p_particles, const AABB &p_aabb) { - - Particles *particles = particles_owner.getornull(p_particles); - ERR_FAIL_COND(!particles); - particles->custom_aabb = p_aabb; - _particles_update_histories(particles); - particles->instance_change_notify(true, false); -} - -void RasterizerStorageGLES3::particles_set_speed_scale(RID p_particles, float p_scale) { - - Particles *particles = particles_owner.getornull(p_particles); - ERR_FAIL_COND(!particles); - - particles->speed_scale = p_scale; -} -void RasterizerStorageGLES3::particles_set_use_local_coordinates(RID p_particles, bool p_enable) { - - Particles *particles = particles_owner.getornull(p_particles); - ERR_FAIL_COND(!particles); - - particles->use_local_coords = p_enable; -} - -void RasterizerStorageGLES3::particles_set_fixed_fps(RID p_particles, int p_fps) { - - Particles *particles = particles_owner.getornull(p_particles); - ERR_FAIL_COND(!particles); - - particles->fixed_fps = p_fps; -} - -void RasterizerStorageGLES3::particles_set_fractional_delta(RID p_particles, bool p_enable) { - - Particles *particles = particles_owner.getornull(p_particles); - ERR_FAIL_COND(!particles); - - particles->fractional_delta = p_enable; -} - -void RasterizerStorageGLES3::particles_set_process_material(RID p_particles, RID p_material) { - - Particles *particles = particles_owner.getornull(p_particles); - ERR_FAIL_COND(!particles); - - particles->process_material = p_material; -} - -void RasterizerStorageGLES3::particles_set_draw_order(RID p_particles, VS::ParticlesDrawOrder p_order) { - - Particles *particles = particles_owner.getornull(p_particles); - ERR_FAIL_COND(!particles); - - particles->draw_order = p_order; - _particles_update_histories(particles); -} - -void RasterizerStorageGLES3::particles_set_draw_passes(RID p_particles, int p_passes) { - - Particles *particles = particles_owner.getornull(p_particles); - ERR_FAIL_COND(!particles); - - particles->draw_passes.resize(p_passes); -} - -void RasterizerStorageGLES3::particles_set_draw_pass_mesh(RID p_particles, int p_pass, RID p_mesh) { - - Particles *particles = particles_owner.getornull(p_particles); - ERR_FAIL_COND(!particles); - ERR_FAIL_INDEX(p_pass, particles->draw_passes.size()); - particles->draw_passes.write[p_pass] = p_mesh; -} - -void RasterizerStorageGLES3::particles_restart(RID p_particles) { - - Particles *particles = particles_owner.getornull(p_particles); - ERR_FAIL_COND(!particles); - - particles->restart_request = true; -} - -void RasterizerStorageGLES3::particles_request_process(RID p_particles) { - - Particles *particles = particles_owner.getornull(p_particles); - ERR_FAIL_COND(!particles); - - if (!particles->particle_element.in_list()) { - particle_update_list.add(&particles->particle_element); - } -} - -AABB RasterizerStorageGLES3::particles_get_current_aabb(RID p_particles) { - - const Particles *particles = particles_owner.getornull(p_particles); - ERR_FAIL_COND_V(!particles, AABB()); - - const float *data; - glBindBuffer(GL_ARRAY_BUFFER, particles->particle_buffers[0]); - -#if defined(GLES_OVER_GL) || defined(__EMSCRIPTEN__) - PoolVector<uint8_t> vector; - vector.resize(particles->amount * 16 * 6); - { - PoolVector<uint8_t>::Write w = vector.write(); - glGetBufferSubData(GL_ARRAY_BUFFER, 0, particles->amount * 16 * 6, w.ptr()); - } - PoolVector<uint8_t>::Read r = vector.read(); - data = reinterpret_cast<const float *>(r.ptr()); -#else - data = (float *)glMapBufferRange(GL_ARRAY_BUFFER, 0, particles->amount * 16 * 6, GL_MAP_READ_BIT); -#endif - AABB aabb; - - Transform inv = particles->emission_transform.affine_inverse(); - - for (int i = 0; i < particles->amount; i++) { - int ofs = i * 24; - Vector3 pos = Vector3(data[ofs + 15], data[ofs + 19], data[ofs + 23]); - if (!particles->use_local_coords) { - pos = inv.xform(pos); - } - if (i == 0) - aabb.position = pos; - else - aabb.expand_to(pos); - } - -#if defined(GLES_OVER_GL) || defined(__EMSCRIPTEN__) - r.release(); - vector = PoolVector<uint8_t>(); -#else - glUnmapBuffer(GL_ARRAY_BUFFER); -#endif - - glBindBuffer(GL_ARRAY_BUFFER, 0); - - float longest_axis = 0; - for (int i = 0; i < particles->draw_passes.size(); i++) { - if (particles->draw_passes[i].is_valid()) { - AABB maabb = mesh_get_aabb(particles->draw_passes[i], RID()); - longest_axis = MAX(maabb.get_longest_axis_size(), longest_axis); - } - } - - aabb.grow_by(longest_axis); - - return aabb; -} - -AABB RasterizerStorageGLES3::particles_get_aabb(RID p_particles) const { - - const Particles *particles = particles_owner.getornull(p_particles); - ERR_FAIL_COND_V(!particles, AABB()); - - return particles->custom_aabb; -} - -void RasterizerStorageGLES3::particles_set_emission_transform(RID p_particles, const Transform &p_transform) { - - Particles *particles = particles_owner.getornull(p_particles); - ERR_FAIL_COND(!particles); - - particles->emission_transform = p_transform; -} - -int RasterizerStorageGLES3::particles_get_draw_passes(RID p_particles) const { - - const Particles *particles = particles_owner.getornull(p_particles); - ERR_FAIL_COND_V(!particles, 0); - - return particles->draw_passes.size(); -} - -RID RasterizerStorageGLES3::particles_get_draw_pass_mesh(RID p_particles, int p_pass) const { - - const Particles *particles = particles_owner.getornull(p_particles); - ERR_FAIL_COND_V(!particles, RID()); - ERR_FAIL_INDEX_V(p_pass, particles->draw_passes.size(), RID()); - - return particles->draw_passes[p_pass]; -} - -void RasterizerStorageGLES3::_particles_process(Particles *p_particles, float p_delta) { - - float new_phase = Math::fmod((float)p_particles->phase + (p_delta / p_particles->lifetime) * p_particles->speed_scale, (float)1.0); - - if (p_particles->clear) { - p_particles->cycle_number = 0; - p_particles->random_seed = Math::rand(); - } else if (new_phase < p_particles->phase) { - if (p_particles->one_shot) { - p_particles->emitting = false; - shaders.particles.set_uniform(ParticlesShaderGLES3::EMITTING, false); - } - p_particles->cycle_number++; - } - - shaders.particles.set_uniform(ParticlesShaderGLES3::SYSTEM_PHASE, new_phase); - shaders.particles.set_uniform(ParticlesShaderGLES3::PREV_SYSTEM_PHASE, p_particles->phase); - p_particles->phase = new_phase; - - shaders.particles.set_uniform(ParticlesShaderGLES3::DELTA, p_delta * p_particles->speed_scale); - shaders.particles.set_uniform(ParticlesShaderGLES3::CLEAR, p_particles->clear); - glUniform1ui(shaders.particles.get_uniform_location(ParticlesShaderGLES3::RANDOM_SEED), p_particles->random_seed); - - if (p_particles->use_local_coords) - shaders.particles.set_uniform(ParticlesShaderGLES3::EMISSION_TRANSFORM, Transform()); - else - shaders.particles.set_uniform(ParticlesShaderGLES3::EMISSION_TRANSFORM, p_particles->emission_transform); - - glUniform1ui(shaders.particles.get_uniform(ParticlesShaderGLES3::CYCLE), p_particles->cycle_number); - - p_particles->clear = false; - - glBindVertexArray(p_particles->particle_vaos[0]); - - glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, p_particles->particle_buffers[1]); - - // GLint size = 0; - // glGetBufferParameteriv(GL_ARRAY_BUFFER, GL_BUFFER_SIZE, &size); - - glBeginTransformFeedback(GL_POINTS); - glDrawArrays(GL_POINTS, 0, p_particles->amount); - glEndTransformFeedback(); - - SWAP(p_particles->particle_buffers[0], p_particles->particle_buffers[1]); - SWAP(p_particles->particle_vaos[0], p_particles->particle_vaos[1]); - - glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, 0); - glBindVertexArray(0); - /* //debug particles :D - glBindBuffer(GL_ARRAY_BUFFER, p_particles->particle_buffers[0]); - - float *data = (float *)glMapBufferRange(GL_ARRAY_BUFFER, 0, p_particles->amount * 16 * 6, GL_MAP_READ_BIT); - for (int i = 0; i < p_particles->amount; i++) { - int ofs = i * 24; - print_line(itos(i) + ":"); - print_line("\tColor: " + Color(data[ofs + 0], data[ofs + 1], data[ofs + 2], data[ofs + 3])); - print_line("\tVelocity: " + Vector3(data[ofs + 4], data[ofs + 5], data[ofs + 6])); - print_line("\tActive: " + itos(data[ofs + 7])); - print_line("\tCustom: " + Color(data[ofs + 8], data[ofs + 9], data[ofs + 10], data[ofs + 11])); - print_line("\tXF X: " + Color(data[ofs + 12], data[ofs + 13], data[ofs + 14], data[ofs + 15])); - print_line("\tXF Y: " + Color(data[ofs + 16], data[ofs + 17], data[ofs + 18], data[ofs + 19])); - print_line("\tXF Z: " + Color(data[ofs + 20], data[ofs + 21], data[ofs + 22], data[ofs + 23])); - } - - glUnmapBuffer(GL_ARRAY_BUFFER); - glBindBuffer(GL_ARRAY_BUFFER, 0); - //*/ -} - -void RasterizerStorageGLES3::update_particles() { - - glEnable(GL_RASTERIZER_DISCARD); - - while (particle_update_list.first()) { - - //use transform feedback to process particles - - Particles *particles = particle_update_list.first()->self(); - - if (particles->restart_request) { - particles->prev_ticks = 0; - particles->phase = 0; - particles->prev_phase = 0; - particles->clear = true; - particles->particle_valid_histories[0] = false; - particles->particle_valid_histories[1] = false; - particles->restart_request = false; - } - - if (particles->inactive && !particles->emitting) { - - particle_update_list.remove(particle_update_list.first()); - continue; - } - - if (particles->emitting) { - if (particles->inactive) { - //restart system from scratch - particles->prev_ticks = 0; - particles->phase = 0; - particles->prev_phase = 0; - particles->clear = true; - particles->particle_valid_histories[0] = false; - particles->particle_valid_histories[1] = false; - } - particles->inactive = false; - particles->inactive_time = 0; - } else { - particles->inactive_time += particles->speed_scale * frame.delta; - if (particles->inactive_time > particles->lifetime * 1.2) { - particles->inactive = true; - particle_update_list.remove(particle_update_list.first()); - continue; - } - } - - Material *material = material_owner.getornull(particles->process_material); - if (!material || !material->shader || material->shader->mode != VS::SHADER_PARTICLES) { - - shaders.particles.set_custom_shader(0); - } else { - shaders.particles.set_custom_shader(material->shader->custom_code_id); - - if (material->ubo_id) { - - glBindBufferBase(GL_UNIFORM_BUFFER, 0, material->ubo_id); - } - - int tc = material->textures.size(); - RID *textures = material->textures.ptrw(); - ShaderLanguage::ShaderNode::Uniform::Hint *texture_hints = material->shader->texture_hints.ptrw(); - - for (int i = 0; i < tc; i++) { - - glActiveTexture(GL_TEXTURE0 + i); - - GLenum target; - GLuint tex; - - RasterizerStorageGLES3::Texture *t = texture_owner.getornull(textures[i]); - - if (!t) { - //check hints - target = GL_TEXTURE_2D; - - switch (texture_hints[i]) { - case ShaderLanguage::ShaderNode::Uniform::HINT_BLACK_ALBEDO: - case ShaderLanguage::ShaderNode::Uniform::HINT_BLACK: { - tex = resources.black_tex; - } break; - case ShaderLanguage::ShaderNode::Uniform::HINT_ANISO: { - tex = resources.aniso_tex; - } break; - case ShaderLanguage::ShaderNode::Uniform::HINT_NORMAL: { - tex = resources.normal_tex; - } break; - default: { - tex = resources.white_tex; - } break; - } - } else { - - t = t->get_ptr(); //resolve for proxies - target = t->target; - tex = t->tex_id; - } - - glBindTexture(target, tex); - } - } - - shaders.particles.set_conditional(ParticlesShaderGLES3::USE_FRACTIONAL_DELTA, particles->fractional_delta); - - shaders.particles.bind(); - - shaders.particles.set_uniform(ParticlesShaderGLES3::TOTAL_PARTICLES, particles->amount); - shaders.particles.set_uniform(ParticlesShaderGLES3::TIME, frame.time[0]); - shaders.particles.set_uniform(ParticlesShaderGLES3::EXPLOSIVENESS, particles->explosiveness); - shaders.particles.set_uniform(ParticlesShaderGLES3::LIFETIME, particles->lifetime); - shaders.particles.set_uniform(ParticlesShaderGLES3::ATTRACTOR_COUNT, 0); - shaders.particles.set_uniform(ParticlesShaderGLES3::EMITTING, particles->emitting); - shaders.particles.set_uniform(ParticlesShaderGLES3::RANDOMNESS, particles->randomness); - - bool zero_time_scale = Engine::get_singleton()->get_time_scale() <= 0.0; - - if (particles->clear && particles->pre_process_time > 0.0) { - - float frame_time; - if (particles->fixed_fps > 0) - frame_time = 1.0 / particles->fixed_fps; - else - frame_time = 1.0 / 30.0; - - float todo = particles->pre_process_time; - - while (todo >= 0) { - _particles_process(particles, frame_time); - todo -= frame_time; - } - } - - if (particles->fixed_fps > 0) { - float frame_time; - float decr; - if (zero_time_scale) { - frame_time = 0.0; - decr = 1.0 / particles->fixed_fps; - } else { - frame_time = 1.0 / particles->fixed_fps; - decr = frame_time; - } - float delta = frame.delta; - if (delta > 0.1) { //avoid recursive stalls if fps goes below 10 - delta = 0.1; - } else if (delta <= 0.0) { //unlikely but.. - delta = 0.001; - } - float todo = particles->frame_remainder + delta; - - while (todo >= frame_time) { - _particles_process(particles, frame_time); - todo -= decr; - } - - particles->frame_remainder = todo; - - } else { - if (zero_time_scale) - _particles_process(particles, 0.0); - else - _particles_process(particles, frame.delta); - } - - particle_update_list.remove(particle_update_list.first()); - - if (particles->histories_enabled) { - - SWAP(particles->particle_buffer_histories[0], particles->particle_buffer_histories[1]); - SWAP(particles->particle_vao_histories[0], particles->particle_vao_histories[1]); - SWAP(particles->particle_valid_histories[0], particles->particle_valid_histories[1]); - - //copy - glBindBuffer(GL_COPY_READ_BUFFER, particles->particle_buffers[0]); - glBindBuffer(GL_COPY_WRITE_BUFFER, particles->particle_buffer_histories[0]); - glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, 0, particles->amount * 24 * sizeof(float)); - - particles->particle_valid_histories[0] = true; - } - - particles->instance_change_notify(true, false); //make sure shadows are updated - } - - glDisable(GL_RASTERIZER_DISCARD); -} - -bool RasterizerStorageGLES3::particles_is_inactive(RID p_particles) const { - - const Particles *particles = particles_owner.getornull(p_particles); - ERR_FAIL_COND_V(!particles, false); - return !particles->emitting && particles->inactive; -} - -//////// - -void RasterizerStorageGLES3::instance_add_skeleton(RID p_skeleton, RasterizerScene::InstanceBase *p_instance) { - - Skeleton *skeleton = skeleton_owner.getornull(p_skeleton); - ERR_FAIL_COND(!skeleton); - - skeleton->instances.insert(p_instance); -} - -void RasterizerStorageGLES3::instance_remove_skeleton(RID p_skeleton, RasterizerScene::InstanceBase *p_instance) { - - Skeleton *skeleton = skeleton_owner.getornull(p_skeleton); - ERR_FAIL_COND(!skeleton); - - skeleton->instances.erase(p_instance); -} - -void RasterizerStorageGLES3::instance_add_dependency(RID p_base, RasterizerScene::InstanceBase *p_instance) { - - Instantiable *inst = NULL; - switch (p_instance->base_type) { - case VS::INSTANCE_MESH: { - inst = mesh_owner.getornull(p_base); - ERR_FAIL_COND(!inst); - } break; - case VS::INSTANCE_MULTIMESH: { - inst = multimesh_owner.getornull(p_base); - ERR_FAIL_COND(!inst); - } break; - case VS::INSTANCE_IMMEDIATE: { - inst = immediate_owner.getornull(p_base); - ERR_FAIL_COND(!inst); - } break; - case VS::INSTANCE_PARTICLES: { - inst = particles_owner.getornull(p_base); - ERR_FAIL_COND(!inst); - } break; - case VS::INSTANCE_REFLECTION_PROBE: { - inst = reflection_probe_owner.getornull(p_base); - ERR_FAIL_COND(!inst); - } break; - case VS::INSTANCE_LIGHT: { - inst = light_owner.getornull(p_base); - ERR_FAIL_COND(!inst); - } break; - case VS::INSTANCE_GI_PROBE: { - inst = gi_probe_owner.getornull(p_base); - ERR_FAIL_COND(!inst); - } break; - case VS::INSTANCE_LIGHTMAP_CAPTURE: { - inst = lightmap_capture_data_owner.getornull(p_base); - ERR_FAIL_COND(!inst); - } break; - default: { - ERR_FAIL(); - } - } - - inst->instance_list.add(&p_instance->dependency_item); -} - -void RasterizerStorageGLES3::instance_remove_dependency(RID p_base, RasterizerScene::InstanceBase *p_instance) { - - Instantiable *inst = NULL; - - switch (p_instance->base_type) { - case VS::INSTANCE_MESH: { - inst = mesh_owner.getornull(p_base); - ERR_FAIL_COND(!inst); - } break; - case VS::INSTANCE_MULTIMESH: { - inst = multimesh_owner.getornull(p_base); - ERR_FAIL_COND(!inst); - } break; - case VS::INSTANCE_IMMEDIATE: { - inst = immediate_owner.getornull(p_base); - ERR_FAIL_COND(!inst); - } break; - case VS::INSTANCE_PARTICLES: { - inst = particles_owner.getornull(p_base); - ERR_FAIL_COND(!inst); - } break; - case VS::INSTANCE_REFLECTION_PROBE: { - inst = reflection_probe_owner.getornull(p_base); - ERR_FAIL_COND(!inst); - } break; - case VS::INSTANCE_LIGHT: { - inst = light_owner.getornull(p_base); - ERR_FAIL_COND(!inst); - } break; - case VS::INSTANCE_GI_PROBE: { - inst = gi_probe_owner.getornull(p_base); - ERR_FAIL_COND(!inst); - } break; - case VS::INSTANCE_LIGHTMAP_CAPTURE: { - inst = lightmap_capture_data_owner.getornull(p_base); - ERR_FAIL_COND(!inst); - } break; - default: { - ERR_FAIL(); - } - } - - inst->instance_list.remove(&p_instance->dependency_item); -} - -/* RENDER TARGET */ - -void RasterizerStorageGLES3::_render_target_clear(RenderTarget *rt) { - - if (rt->fbo) { - glDeleteFramebuffers(1, &rt->fbo); - glDeleteTextures(1, &rt->color); - rt->fbo = 0; - } - - if (rt->buffers.active) { - glDeleteFramebuffers(1, &rt->buffers.fbo); - glDeleteRenderbuffers(1, &rt->buffers.depth); - glDeleteRenderbuffers(1, &rt->buffers.diffuse); - if (rt->buffers.effects_active) { - glDeleteRenderbuffers(1, &rt->buffers.specular); - glDeleteRenderbuffers(1, &rt->buffers.normal_rough); - glDeleteRenderbuffers(1, &rt->buffers.sss); - glDeleteFramebuffers(1, &rt->buffers.effect_fbo); - glDeleteTextures(1, &rt->buffers.effect); - } - - rt->buffers.effects_active = false; - rt->buffers.active = false; - } - - if (rt->depth) { - glDeleteTextures(1, &rt->depth); - rt->depth = 0; - } - - if (rt->effects.ssao.blur_fbo[0]) { - glDeleteFramebuffers(1, &rt->effects.ssao.blur_fbo[0]); - glDeleteTextures(1, &rt->effects.ssao.blur_red[0]); - glDeleteFramebuffers(1, &rt->effects.ssao.blur_fbo[1]); - glDeleteTextures(1, &rt->effects.ssao.blur_red[1]); - for (int i = 0; i < rt->effects.ssao.depth_mipmap_fbos.size(); i++) { - glDeleteFramebuffers(1, &rt->effects.ssao.depth_mipmap_fbos[i]); - } - - rt->effects.ssao.depth_mipmap_fbos.clear(); - - glDeleteTextures(1, &rt->effects.ssao.linear_depth); - - rt->effects.ssao.blur_fbo[0] = 0; - rt->effects.ssao.blur_fbo[1] = 0; - } - - if (rt->exposure.fbo) { - glDeleteFramebuffers(1, &rt->exposure.fbo); - glDeleteTextures(1, &rt->exposure.color); - rt->exposure.fbo = 0; - } - - if (rt->external.fbo != 0) { - // free this - glDeleteFramebuffers(1, &rt->external.fbo); - - // clean up our texture - Texture *t = texture_owner.get(rt->external.texture); - t->alloc_height = 0; - t->alloc_width = 0; - t->width = 0; - t->height = 0; - t->active = false; - texture_owner.free(rt->external.texture); - memdelete(t); - - rt->external.fbo = 0; - } - - Texture *tex = texture_owner.get(rt->texture); - tex->alloc_height = 0; - tex->alloc_width = 0; - tex->width = 0; - tex->height = 0; - tex->active = false; - - for (int i = 0; i < 2; i++) { - if (rt->effects.mip_maps[i].color) { - for (int j = 0; j < rt->effects.mip_maps[i].sizes.size(); j++) { - glDeleteFramebuffers(1, &rt->effects.mip_maps[i].sizes[j].fbo); - } - - glDeleteTextures(1, &rt->effects.mip_maps[i].color); - rt->effects.mip_maps[i].sizes.clear(); - rt->effects.mip_maps[i].levels = 0; - rt->effects.mip_maps[i].color = 0; - } - } - - /* - if (rt->effects.screen_space_depth) { - glDeleteTextures(1,&rt->effects.screen_space_depth); - rt->effects.screen_space_depth=0; - - } -*/ -} - -void RasterizerStorageGLES3::_render_target_allocate(RenderTarget *rt) { - - if (rt->width <= 0 || rt->height <= 0) - return; - - GLuint color_internal_format; - GLuint color_format; - GLuint color_type; - Image::Format image_format; - - bool hdr = rt->flags[RENDER_TARGET_HDR] && config.framebuffer_half_float_supported; - //hdr = false; - - if (!hdr || rt->flags[RENDER_TARGET_NO_3D]) { - - if (rt->flags[RENDER_TARGET_NO_3D_EFFECTS] && !rt->flags[RENDER_TARGET_TRANSPARENT]) { - //if this is not used, linear colorspace looks pretty bad - //this is the default mode used for mobile - color_internal_format = GL_RGB10_A2; - color_format = GL_RGBA; - color_type = GL_UNSIGNED_INT_2_10_10_10_REV; - image_format = Image::FORMAT_RGBA8; - } else { - - color_internal_format = GL_RGBA8; - color_format = GL_RGBA; - color_type = GL_UNSIGNED_BYTE; - image_format = Image::FORMAT_RGBA8; - } - } else { - color_internal_format = GL_RGBA16F; - color_format = GL_RGBA; - color_type = GL_HALF_FLOAT; - image_format = Image::FORMAT_RGBAH; - } - - { - /* FRONT FBO */ - - glActiveTexture(GL_TEXTURE0); - - glGenFramebuffers(1, &rt->fbo); - glBindFramebuffer(GL_FRAMEBUFFER, rt->fbo); - - glGenTextures(1, &rt->depth); - glBindTexture(GL_TEXTURE_2D, rt->depth); - glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, rt->width, rt->height, 0, - GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - 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); - - glGenTextures(1, &rt->color); - glBindTexture(GL_TEXTURE_2D, rt->color); - - glTexImage2D(GL_TEXTURE_2D, 0, color_internal_format, rt->width, rt->height, 0, color_format, color_type, NULL); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - 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_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->color, 0); - - GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); - glBindFramebuffer(GL_FRAMEBUFFER, RasterizerStorageGLES3::system_fbo); - - if (status != GL_FRAMEBUFFER_COMPLETE) { - printf("framebuffer fail, status: %x\n", status); - } - - ERR_FAIL_COND(status != GL_FRAMEBUFFER_COMPLETE); - - Texture *tex = texture_owner.get(rt->texture); - tex->format = image_format; - tex->gl_format_cache = color_format; - tex->gl_type_cache = color_type; - tex->gl_internal_format_cache = color_internal_format; - tex->tex_id = rt->color; - tex->width = rt->width; - tex->alloc_width = rt->width; - tex->height = rt->height; - tex->alloc_height = rt->height; - tex->active = true; - - texture_set_flags(rt->texture, tex->flags); - } - - /* BACK FBO */ - - if (!rt->flags[RENDER_TARGET_NO_3D] && (!rt->flags[RENDER_TARGET_NO_3D_EFFECTS] || rt->msaa != VS::VIEWPORT_MSAA_DISABLED)) { - - rt->buffers.active = true; - - static const int msaa_value[] = { 0, 2, 4, 8, 16, 4, 16 }; // MSAA_EXT_nX is a GLES2 temporary hack ignored in GLES3 for now... - int msaa = msaa_value[rt->msaa]; - - int max_samples = 0; - glGetIntegerv(GL_MAX_SAMPLES, &max_samples); - if (msaa > max_samples) { - WARN_PRINTS("MSAA must be <= GL_MAX_SAMPLES, falling-back to GL_MAX_SAMPLES = " + itos(max_samples)); - msaa = max_samples; - } - - //regular fbo - glGenFramebuffers(1, &rt->buffers.fbo); - glBindFramebuffer(GL_FRAMEBUFFER, rt->buffers.fbo); - - glGenRenderbuffers(1, &rt->buffers.depth); - glBindRenderbuffer(GL_RENDERBUFFER, rt->buffers.depth); - if (msaa == 0) - glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, rt->width, rt->height); - else - glRenderbufferStorageMultisample(GL_RENDERBUFFER, msaa, GL_DEPTH_COMPONENT24, rt->width, rt->height); - - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rt->buffers.depth); - - glGenRenderbuffers(1, &rt->buffers.diffuse); - glBindRenderbuffer(GL_RENDERBUFFER, rt->buffers.diffuse); - - if (msaa == 0) - glRenderbufferStorage(GL_RENDERBUFFER, color_internal_format, rt->width, rt->height); - else - glRenderbufferStorageMultisample(GL_RENDERBUFFER, msaa, color_internal_format, rt->width, rt->height); - - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rt->buffers.diffuse); - - if (!rt->flags[RENDER_TARGET_NO_3D_EFFECTS]) { - - rt->buffers.effects_active = true; - glGenRenderbuffers(1, &rt->buffers.specular); - glBindRenderbuffer(GL_RENDERBUFFER, rt->buffers.specular); - - if (msaa == 0) - glRenderbufferStorage(GL_RENDERBUFFER, color_internal_format, rt->width, rt->height); - else - glRenderbufferStorageMultisample(GL_RENDERBUFFER, msaa, color_internal_format, rt->width, rt->height); - - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_RENDERBUFFER, rt->buffers.specular); - - glGenRenderbuffers(1, &rt->buffers.normal_rough); - glBindRenderbuffer(GL_RENDERBUFFER, rt->buffers.normal_rough); - - if (msaa == 0) - glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, rt->width, rt->height); - else - glRenderbufferStorageMultisample(GL_RENDERBUFFER, msaa, GL_RGBA8, rt->width, rt->height); - - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_RENDERBUFFER, rt->buffers.normal_rough); - - glGenRenderbuffers(1, &rt->buffers.sss); - glBindRenderbuffer(GL_RENDERBUFFER, rt->buffers.sss); - - if (msaa == 0) - glRenderbufferStorage(GL_RENDERBUFFER, GL_R8, rt->width, rt->height); - else - glRenderbufferStorageMultisample(GL_RENDERBUFFER, msaa, GL_R8, rt->width, rt->height); - - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT3, GL_RENDERBUFFER, rt->buffers.sss); - - GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); - glBindFramebuffer(GL_FRAMEBUFFER, RasterizerStorageGLES3::system_fbo); - - if (status != GL_FRAMEBUFFER_COMPLETE) { - printf("err status: %x\n", status); - _render_target_clear(rt); - ERR_FAIL_COND(status != GL_FRAMEBUFFER_COMPLETE); - } - - glBindRenderbuffer(GL_RENDERBUFFER, 0); - - // effect resolver - - glGenFramebuffers(1, &rt->buffers.effect_fbo); - glBindFramebuffer(GL_FRAMEBUFFER, rt->buffers.effect_fbo); - - glGenTextures(1, &rt->buffers.effect); - glBindTexture(GL_TEXTURE_2D, rt->buffers.effect); - glTexImage2D(GL_TEXTURE_2D, 0, color_internal_format, rt->width, rt->height, 0, - color_format, color_type, NULL); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - 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_COLOR_ATTACHMENT0, - GL_TEXTURE_2D, rt->buffers.effect, 0); - - status = glCheckFramebufferStatus(GL_FRAMEBUFFER); - glBindFramebuffer(GL_FRAMEBUFFER, RasterizerStorageGLES3::system_fbo); - - if (status != GL_FRAMEBUFFER_COMPLETE) { - printf("err status: %x\n", status); - _render_target_clear(rt); - ERR_FAIL_COND(status != GL_FRAMEBUFFER_COMPLETE); - } - - ///////////////// ssao - - //AO strength textures - for (int i = 0; i < 2; i++) { - - glGenFramebuffers(1, &rt->effects.ssao.blur_fbo[i]); - glBindFramebuffer(GL_FRAMEBUFFER, rt->effects.ssao.blur_fbo[i]); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, - GL_TEXTURE_2D, rt->depth, 0); - - glGenTextures(1, &rt->effects.ssao.blur_red[i]); - glBindTexture(GL_TEXTURE_2D, rt->effects.ssao.blur_red[i]); - - glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, rt->width, rt->height, 0, GL_RED, GL_UNSIGNED_BYTE, NULL); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - 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_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->effects.ssao.blur_red[i], 0); - - status = glCheckFramebufferStatus(GL_FRAMEBUFFER); - if (status != GL_FRAMEBUFFER_COMPLETE) { - _render_target_clear(rt); - ERR_FAIL_COND(status != GL_FRAMEBUFFER_COMPLETE); - } - } - //5 mip levels for depth texture, but base is read separately - - glGenTextures(1, &rt->effects.ssao.linear_depth); - glBindTexture(GL_TEXTURE_2D, rt->effects.ssao.linear_depth); - - int ssao_w = rt->width / 2; - int ssao_h = rt->height / 2; - - for (int i = 0; i < 4; i++) { //5, but 4 mips, base is read directly to save bw - - glTexImage2D(GL_TEXTURE_2D, i, GL_R16UI, ssao_w, ssao_h, 0, GL_RED_INTEGER, GL_UNSIGNED_SHORT, NULL); - ssao_w >>= 1; - ssao_h >>= 1; - } - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 3); - - for (int i = 0; i < 4; i++) { //5, but 4 mips, base is read directly to save bw - - GLuint fbo; - glGenFramebuffers(1, &fbo); - glBindFramebuffer(GL_FRAMEBUFFER, fbo); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->effects.ssao.linear_depth, i); - rt->effects.ssao.depth_mipmap_fbos.push_back(fbo); - } - - //////Exposure - - glGenFramebuffers(1, &rt->exposure.fbo); - glBindFramebuffer(GL_FRAMEBUFFER, rt->exposure.fbo); - - glGenTextures(1, &rt->exposure.color); - glBindTexture(GL_TEXTURE_2D, rt->exposure.color); - if (config.framebuffer_float_supported) { - glTexImage2D(GL_TEXTURE_2D, 0, GL_R32F, 1, 1, 0, GL_RED, GL_FLOAT, NULL); - } else if (config.framebuffer_half_float_supported) { - glTexImage2D(GL_TEXTURE_2D, 0, GL_R16F, 1, 1, 0, GL_RED, GL_HALF_FLOAT, NULL); - } else { - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB10_A2, 1, 1, 0, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV, NULL); - } - - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->exposure.color, 0); - - status = glCheckFramebufferStatus(GL_FRAMEBUFFER); - if (status != GL_FRAMEBUFFER_COMPLETE) { - _render_target_clear(rt); - ERR_FAIL_COND(status != GL_FRAMEBUFFER_COMPLETE); - } - } else { - rt->buffers.effects_active = false; - } - } else { - rt->buffers.active = false; - rt->buffers.effects_active = true; - } - - if (!rt->flags[RENDER_TARGET_NO_SAMPLING] && rt->width >= 2 && rt->height >= 2) { - - for (int i = 0; i < 2; i++) { - - ERR_FAIL_COND(rt->effects.mip_maps[i].sizes.size()); - int w = rt->width; - int h = rt->height; - - if (i > 0) { - w >>= 1; - h >>= 1; - } - - glGenTextures(1, &rt->effects.mip_maps[i].color); - glBindTexture(GL_TEXTURE_2D, rt->effects.mip_maps[i].color); - - int level = 0; - int fb_w = w; - int fb_h = h; - - while (true) { - - RenderTarget::Effects::MipMaps::Size mm; - mm.width = w; - mm.height = h; - rt->effects.mip_maps[i].sizes.push_back(mm); - - w >>= 1; - h >>= 1; - - if (w < 2 || h < 2) - break; - - level++; - } - - glTexStorage2DCustom(GL_TEXTURE_2D, level + 1, color_internal_format, fb_w, fb_h, color_format, color_type); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, level); - glDisable(GL_SCISSOR_TEST); - glColorMask(1, 1, 1, 1); - if (!rt->buffers.active) { - glDepthMask(GL_TRUE); - } - - for (int j = 0; j < rt->effects.mip_maps[i].sizes.size(); j++) { - - RenderTarget::Effects::MipMaps::Size &mm = rt->effects.mip_maps[i].sizes.write[j]; - - glGenFramebuffers(1, &mm.fbo); - glBindFramebuffer(GL_FRAMEBUFFER, mm.fbo); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->effects.mip_maps[i].color, j); - bool used_depth = false; - if (j == 0 && i == 0) { //use always - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, rt->depth, 0); - used_depth = true; - } - - GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); - if (status != GL_FRAMEBUFFER_COMPLETE) { - _render_target_clear(rt); - ERR_FAIL_COND(status != GL_FRAMEBUFFER_COMPLETE); - } - - float zero[4] = { 1, 0, 1, 0 }; - glViewport(0, 0, rt->effects.mip_maps[i].sizes[j].width, rt->effects.mip_maps[i].sizes[j].height); - glClearBufferfv(GL_COLOR, 0, zero); - if (used_depth) { - glClearDepth(1.0); - glClear(GL_DEPTH_BUFFER_BIT); - } - } - - glBindFramebuffer(GL_FRAMEBUFFER, RasterizerStorageGLES3::system_fbo); - rt->effects.mip_maps[i].levels = level; - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - } - } -} - -RID RasterizerStorageGLES3::render_target_create() { - - RenderTarget *rt = memnew(RenderTarget); - - Texture *t = memnew(Texture); - - t->type = VS::TEXTURE_TYPE_2D; - t->flags = 0; - t->width = 0; - t->height = 0; - t->alloc_height = 0; - t->alloc_width = 0; - t->format = Image::FORMAT_R8; - t->target = GL_TEXTURE_2D; - t->gl_format_cache = 0; - t->gl_internal_format_cache = 0; - t->gl_type_cache = 0; - t->data_size = 0; - t->compressed = false; - t->srgb = false; - t->total_data_size = 0; - t->ignore_mipmaps = false; - t->mipmaps = 1; - t->active = true; - t->tex_id = 0; - t->render_target = rt; - - rt->texture = texture_owner.make_rid(t); - - return render_target_owner.make_rid(rt); -} - -void RasterizerStorageGLES3::render_target_set_position(RID p_render_target, int p_x, int p_y) { - //only used in GLES2 -} - -void RasterizerStorageGLES3::render_target_set_size(RID p_render_target, int p_width, int p_height) { - - RenderTarget *rt = render_target_owner.getornull(p_render_target); - ERR_FAIL_COND(!rt); - - if (rt->width == p_width && rt->height == p_height) - return; - - _render_target_clear(rt); - rt->width = p_width; - rt->height = p_height; - _render_target_allocate(rt); -} - -RID RasterizerStorageGLES3::render_target_get_texture(RID p_render_target) const { - - RenderTarget *rt = render_target_owner.getornull(p_render_target); - ERR_FAIL_COND_V(!rt, RID()); - - if (rt->external.fbo == 0) { - return rt->texture; - } else { - return rt->external.texture; - } -} - -void RasterizerStorageGLES3::render_target_set_external_texture(RID p_render_target, unsigned int p_texture_id) { - RenderTarget *rt = render_target_owner.getornull(p_render_target); - ERR_FAIL_COND(!rt); - - if (p_texture_id == 0) { - if (rt->external.fbo != 0) { - // free this - glDeleteFramebuffers(1, &rt->external.fbo); - - // clean up our texture - Texture *t = texture_owner.get(rt->external.texture); - t->alloc_height = 0; - t->alloc_width = 0; - t->width = 0; - t->height = 0; - t->active = false; - texture_owner.free(rt->external.texture); - memdelete(t); - - rt->external.fbo = 0; - } - } else { - Texture *t; - - if (rt->external.fbo == 0) { - // create our fbo - glGenFramebuffers(1, &rt->external.fbo); - glBindFramebuffer(GL_FRAMEBUFFER, rt->external.fbo); - - // allocate a texture - t = memnew(Texture); - - t->type = VS::TEXTURE_TYPE_2D; - t->flags = 0; - t->width = 0; - t->height = 0; - t->alloc_height = 0; - t->alloc_width = 0; - t->format = Image::FORMAT_RGBA8; - t->target = GL_TEXTURE_2D; - t->gl_format_cache = 0; - t->gl_internal_format_cache = 0; - t->gl_type_cache = 0; - t->data_size = 0; - t->compressed = false; - t->srgb = false; - t->total_data_size = 0; - t->ignore_mipmaps = false; - t->mipmaps = 1; - t->active = true; - t->tex_id = 0; - t->render_target = rt; - - rt->external.texture = texture_owner.make_rid(t); - } else { - // bind our frame buffer - glBindFramebuffer(GL_FRAMEBUFFER, rt->external.fbo); - - // find our texture - t = texture_owner.get(rt->external.texture); - } - - // set our texture - t->tex_id = p_texture_id; - - // size shouldn't be different - t->width = rt->width; - t->height = rt->height; - t->alloc_height = rt->width; - t->alloc_width = rt->height; - - // is there a point to setting the internal formats? we don't know them.. - - // set our texture as the destination for our framebuffer - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, p_texture_id, 0); - - // check status and unbind - GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); - glBindFramebuffer(GL_FRAMEBUFFER, RasterizerStorageGLES3::system_fbo); - - if (status != GL_FRAMEBUFFER_COMPLETE) { - printf("framebuffer fail, status: %x\n", status); - } - - ERR_FAIL_COND(status != GL_FRAMEBUFFER_COMPLETE); - } -} - -void RasterizerStorageGLES3::render_target_set_flag(RID p_render_target, RenderTargetFlags p_flag, bool p_value) { - - RenderTarget *rt = render_target_owner.getornull(p_render_target); - ERR_FAIL_COND(!rt); - - rt->flags[p_flag] = p_value; - - switch (p_flag) { - case RENDER_TARGET_HDR: - case RENDER_TARGET_NO_3D: - case RENDER_TARGET_NO_SAMPLING: - case RENDER_TARGET_NO_3D_EFFECTS: { - //must reset for these formats - _render_target_clear(rt); - _render_target_allocate(rt); - - } break; - default: { - } - } -} -bool RasterizerStorageGLES3::render_target_was_used(RID p_render_target) { - - RenderTarget *rt = render_target_owner.getornull(p_render_target); - ERR_FAIL_COND_V(!rt, false); - - return rt->used_in_frame; -} - -void RasterizerStorageGLES3::render_target_clear_used(RID p_render_target) { - - RenderTarget *rt = render_target_owner.getornull(p_render_target); - ERR_FAIL_COND(!rt); - - rt->used_in_frame = false; -} - -void RasterizerStorageGLES3::render_target_set_msaa(RID p_render_target, VS::ViewportMSAA p_msaa) { - - RenderTarget *rt = render_target_owner.getornull(p_render_target); - ERR_FAIL_COND(!rt); - - if (rt->msaa == p_msaa) - return; - - _render_target_clear(rt); - rt->msaa = p_msaa; - _render_target_allocate(rt); -} - -/* CANVAS SHADOW */ - -RID RasterizerStorageGLES3::canvas_light_shadow_buffer_create(int p_width) { - - CanvasLightShadow *cls = memnew(CanvasLightShadow); - if (p_width > config.max_texture_size) - p_width = config.max_texture_size; - - cls->size = p_width; - cls->height = 16; - - glActiveTexture(GL_TEXTURE0); - - glGenFramebuffers(1, &cls->fbo); - glBindFramebuffer(GL_FRAMEBUFFER, cls->fbo); - - glGenRenderbuffers(1, &cls->depth); - glBindRenderbuffer(GL_RENDERBUFFER, cls->depth); - glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, cls->size, cls->height); - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, cls->depth); - glBindRenderbuffer(GL_RENDERBUFFER, 0); - - glGenTextures(1, &cls->distance); - glBindTexture(GL_TEXTURE_2D, cls->distance); - if (config.use_rgba_2d_shadows) { - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, cls->size, cls->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); - } else { - glTexImage2D(GL_TEXTURE_2D, 0, GL_R32F, cls->size, cls->height, 0, GL_RED, GL_FLOAT, NULL); - } - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - 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_COLOR_ATTACHMENT0, GL_TEXTURE_2D, cls->distance, 0); - - GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); - //printf("errnum: %x\n",status); - glBindFramebuffer(GL_FRAMEBUFFER, RasterizerStorageGLES3::system_fbo); - - if (status != GL_FRAMEBUFFER_COMPLETE) { - memdelete(cls); - ERR_FAIL_COND_V(status != GL_FRAMEBUFFER_COMPLETE, RID()); - } - - return canvas_light_shadow_owner.make_rid(cls); -} - -/* LIGHT SHADOW MAPPING */ - -RID RasterizerStorageGLES3::canvas_light_occluder_create() { - - CanvasOccluder *co = memnew(CanvasOccluder); - co->index_id = 0; - co->vertex_id = 0; - co->len = 0; - glGenVertexArrays(1, &co->array_id); - - return canvas_occluder_owner.make_rid(co); -} - -void RasterizerStorageGLES3::canvas_light_occluder_set_polylines(RID p_occluder, const PoolVector<Vector2> &p_lines) { - - CanvasOccluder *co = canvas_occluder_owner.get(p_occluder); - ERR_FAIL_COND(!co); - - co->lines = p_lines; - - if (p_lines.size() != co->len) { - - if (co->index_id) - glDeleteBuffers(1, &co->index_id); - if (co->vertex_id) - glDeleteBuffers(1, &co->vertex_id); - - co->index_id = 0; - co->vertex_id = 0; - co->len = 0; - } - - if (p_lines.size()) { - - PoolVector<float> geometry; - PoolVector<uint16_t> indices; - int lc = p_lines.size(); - - geometry.resize(lc * 6); - indices.resize(lc * 3); - - PoolVector<float>::Write vw = geometry.write(); - PoolVector<uint16_t>::Write iw = indices.write(); - - PoolVector<Vector2>::Read lr = p_lines.read(); - - const int POLY_HEIGHT = 16384; - - for (int i = 0; i < lc / 2; i++) { - - vw[i * 12 + 0] = lr[i * 2 + 0].x; - vw[i * 12 + 1] = lr[i * 2 + 0].y; - vw[i * 12 + 2] = POLY_HEIGHT; - - vw[i * 12 + 3] = lr[i * 2 + 1].x; - vw[i * 12 + 4] = lr[i * 2 + 1].y; - vw[i * 12 + 5] = POLY_HEIGHT; - - vw[i * 12 + 6] = lr[i * 2 + 1].x; - vw[i * 12 + 7] = lr[i * 2 + 1].y; - vw[i * 12 + 8] = -POLY_HEIGHT; - - vw[i * 12 + 9] = lr[i * 2 + 0].x; - vw[i * 12 + 10] = lr[i * 2 + 0].y; - vw[i * 12 + 11] = -POLY_HEIGHT; - - iw[i * 6 + 0] = i * 4 + 0; - iw[i * 6 + 1] = i * 4 + 1; - iw[i * 6 + 2] = i * 4 + 2; - - iw[i * 6 + 3] = i * 4 + 2; - iw[i * 6 + 4] = i * 4 + 3; - iw[i * 6 + 5] = i * 4 + 0; - } - - //if same buffer len is being set, just use BufferSubData to avoid a pipeline flush - - if (!co->vertex_id) { - glGenBuffers(1, &co->vertex_id); - glBindBuffer(GL_ARRAY_BUFFER, co->vertex_id); - glBufferData(GL_ARRAY_BUFFER, lc * 6 * sizeof(real_t), vw.ptr(), GL_STATIC_DRAW); - } else { - - glBindBuffer(GL_ARRAY_BUFFER, co->vertex_id); - glBufferSubData(GL_ARRAY_BUFFER, 0, lc * 6 * sizeof(real_t), vw.ptr()); - } - - glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind - - if (!co->index_id) { - - glGenBuffers(1, &co->index_id); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, co->index_id); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, lc * 3 * sizeof(uint16_t), iw.ptr(), GL_DYNAMIC_DRAW); - } else { - - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, co->index_id); - glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, lc * 3 * sizeof(uint16_t), iw.ptr()); - } - - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); //unbind - - co->len = lc; - glBindVertexArray(co->array_id); - glBindBuffer(GL_ARRAY_BUFFER, co->vertex_id); - glEnableVertexAttribArray(VS::ARRAY_VERTEX); - glVertexAttribPointer(VS::ARRAY_VERTEX, 3, GL_FLOAT, false, 0, 0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, co->index_id); - glBindVertexArray(0); - } -} - -VS::InstanceType RasterizerStorageGLES3::get_base_type(RID p_rid) const { - - if (mesh_owner.owns(p_rid)) { - return VS::INSTANCE_MESH; - } - - if (multimesh_owner.owns(p_rid)) { - return VS::INSTANCE_MULTIMESH; - } - - if (immediate_owner.owns(p_rid)) { - return VS::INSTANCE_IMMEDIATE; - } - - if (particles_owner.owns(p_rid)) { - return VS::INSTANCE_PARTICLES; - } - - if (light_owner.owns(p_rid)) { - return VS::INSTANCE_LIGHT; - } - - if (reflection_probe_owner.owns(p_rid)) { - return VS::INSTANCE_REFLECTION_PROBE; - } - - if (gi_probe_owner.owns(p_rid)) { - return VS::INSTANCE_GI_PROBE; - } - - if (lightmap_capture_data_owner.owns(p_rid)) { - return VS::INSTANCE_LIGHTMAP_CAPTURE; - } - - return VS::INSTANCE_NONE; -} - -bool RasterizerStorageGLES3::free(RID p_rid) { - - if (render_target_owner.owns(p_rid)) { - - RenderTarget *rt = render_target_owner.getornull(p_rid); - _render_target_clear(rt); - Texture *t = texture_owner.get(rt->texture); - texture_owner.free(rt->texture); - memdelete(t); - render_target_owner.free(p_rid); - memdelete(rt); - - } else if (texture_owner.owns(p_rid)) { - // delete the texture - Texture *texture = texture_owner.get(p_rid); - ERR_FAIL_COND_V(texture->render_target, true); //can't free the render target texture, dude - info.texture_mem -= texture->total_data_size; - texture_owner.free(p_rid); - memdelete(texture); - - } else if (sky_owner.owns(p_rid)) { - // delete the sky - Sky *sky = sky_owner.get(p_rid); - sky_set_texture(p_rid, RID(), 256); - sky_owner.free(p_rid); - memdelete(sky); - - } else if (shader_owner.owns(p_rid)) { - - // delete the texture - Shader *shader = shader_owner.get(p_rid); - - if (shader->shader && shader->custom_code_id) - shader->shader->free_custom_shader(shader->custom_code_id); - - if (shader->dirty_list.in_list()) - _shader_dirty_list.remove(&shader->dirty_list); - - while (shader->materials.first()) { - - Material *mat = shader->materials.first()->self(); - - mat->shader = NULL; - _material_make_dirty(mat); - - shader->materials.remove(shader->materials.first()); - } - - //material_shader.free_custom_shader(shader->custom_code_id); - shader_owner.free(p_rid); - memdelete(shader); - - } else if (material_owner.owns(p_rid)) { - - // delete the texture - Material *material = material_owner.get(p_rid); - - if (material->shader) { - material->shader->materials.remove(&material->list); - } - - if (material->ubo_id) { - glDeleteBuffers(1, &material->ubo_id); - } - - //remove from owners - for (Map<Geometry *, int>::Element *E = material->geometry_owners.front(); E; E = E->next()) { - - Geometry *g = E->key(); - g->material = RID(); - } - for (Map<RasterizerScene::InstanceBase *, int>::Element *E = material->instance_owners.front(); E; E = E->next()) { - RasterizerScene::InstanceBase *ins = E->key(); - if (ins->material_override == p_rid) { - ins->material_override = RID(); - } - - for (int i = 0; i < ins->materials.size(); i++) { - if (ins->materials[i] == p_rid) { - ins->materials.write[i] = RID(); - } - } - } - - material_owner.free(p_rid); - memdelete(material); - - } else if (skeleton_owner.owns(p_rid)) { - - // delete the texture - Skeleton *skeleton = skeleton_owner.get(p_rid); - if (skeleton->update_list.in_list()) { - skeleton_update_list.remove(&skeleton->update_list); - } - - for (Set<RasterizerScene::InstanceBase *>::Element *E = skeleton->instances.front(); E; E = E->next()) { - E->get()->skeleton = RID(); - } - - skeleton_allocate(p_rid, 0, false); - - glDeleteTextures(1, &skeleton->texture); - skeleton_owner.free(p_rid); - memdelete(skeleton); - - } else if (mesh_owner.owns(p_rid)) { - - // delete the texture - Mesh *mesh = mesh_owner.get(p_rid); - mesh->instance_remove_deps(); - mesh_clear(p_rid); - - while (mesh->multimeshes.first()) { - MultiMesh *multimesh = mesh->multimeshes.first()->self(); - multimesh->mesh = RID(); - multimesh->dirty_aabb = true; - mesh->multimeshes.remove(mesh->multimeshes.first()); - - if (!multimesh->update_list.in_list()) { - multimesh_update_list.add(&multimesh->update_list); - } - } - - mesh_owner.free(p_rid); - memdelete(mesh); - - } else if (multimesh_owner.owns(p_rid)) { - - // delete the texture - MultiMesh *multimesh = multimesh_owner.get(p_rid); - multimesh->instance_remove_deps(); - - if (multimesh->mesh.is_valid()) { - Mesh *mesh = mesh_owner.getornull(multimesh->mesh); - if (mesh) { - mesh->multimeshes.remove(&multimesh->mesh_list); - } - } - - multimesh_allocate(p_rid, 0, VS::MULTIMESH_TRANSFORM_2D, VS::MULTIMESH_COLOR_NONE); //frees multimesh - update_dirty_multimeshes(); - - multimesh_owner.free(p_rid); - memdelete(multimesh); - } else if (immediate_owner.owns(p_rid)) { - - Immediate *immediate = immediate_owner.get(p_rid); - immediate->instance_remove_deps(); - - immediate_owner.free(p_rid); - memdelete(immediate); - } else if (light_owner.owns(p_rid)) { - - // delete the texture - Light *light = light_owner.get(p_rid); - light->instance_remove_deps(); - - light_owner.free(p_rid); - memdelete(light); - - } else if (reflection_probe_owner.owns(p_rid)) { - - // delete the texture - ReflectionProbe *reflection_probe = reflection_probe_owner.get(p_rid); - reflection_probe->instance_remove_deps(); - - reflection_probe_owner.free(p_rid); - memdelete(reflection_probe); - - } else if (gi_probe_owner.owns(p_rid)) { - - // delete the texture - GIProbe *gi_probe = gi_probe_owner.get(p_rid); - gi_probe->instance_remove_deps(); - - gi_probe_owner.free(p_rid); - memdelete(gi_probe); - } else if (gi_probe_data_owner.owns(p_rid)) { - - // delete the texture - GIProbeData *gi_probe_data = gi_probe_data_owner.get(p_rid); - - glDeleteTextures(1, &gi_probe_data->tex_id); - gi_probe_data_owner.free(p_rid); - memdelete(gi_probe_data); - } else if (lightmap_capture_data_owner.owns(p_rid)) { - - // delete the texture - LightmapCapture *lightmap_capture = lightmap_capture_data_owner.get(p_rid); - lightmap_capture->instance_remove_deps(); - - lightmap_capture_data_owner.free(p_rid); - memdelete(lightmap_capture); - - } else if (canvas_occluder_owner.owns(p_rid)) { - - CanvasOccluder *co = canvas_occluder_owner.get(p_rid); - if (co->index_id) - glDeleteBuffers(1, &co->index_id); - if (co->vertex_id) - glDeleteBuffers(1, &co->vertex_id); - - glDeleteVertexArrays(1, &co->array_id); - - canvas_occluder_owner.free(p_rid); - memdelete(co); - - } else if (canvas_light_shadow_owner.owns(p_rid)) { - - CanvasLightShadow *cls = canvas_light_shadow_owner.get(p_rid); - glDeleteFramebuffers(1, &cls->fbo); - glDeleteRenderbuffers(1, &cls->depth); - glDeleteTextures(1, &cls->distance); - canvas_light_shadow_owner.free(p_rid); - memdelete(cls); - } else if (particles_owner.owns(p_rid)) { - Particles *particles = particles_owner.get(p_rid); - particles->instance_remove_deps(); - particles_owner.free(p_rid); - memdelete(particles); - } else { - return false; - } - - return true; -} - -bool RasterizerStorageGLES3::has_os_feature(const String &p_feature) const { - - if (p_feature == "bptc") - return config.bptc_supported; - - if (p_feature == "s3tc") - return config.s3tc_supported; - - if (p_feature == "etc") - return config.etc_supported; - - if (p_feature == "etc2") - return config.etc2_supported; - - if (p_feature == "pvrtc") - return config.pvrtc_supported; - - return false; -} - -//////////////////////////////////////////// - -void RasterizerStorageGLES3::set_debug_generate_wireframes(bool p_generate) { - - config.generate_wireframes = p_generate; -} - -void RasterizerStorageGLES3::render_info_begin_capture() { - - info.snap = info.render; -} - -void RasterizerStorageGLES3::render_info_end_capture() { - - info.snap.object_count = info.render.object_count - info.snap.object_count; - info.snap.draw_call_count = info.render.draw_call_count - info.snap.draw_call_count; - info.snap.material_switch_count = info.render.material_switch_count - info.snap.material_switch_count; - info.snap.surface_switch_count = info.render.surface_switch_count - info.snap.surface_switch_count; - info.snap.shader_rebind_count = info.render.shader_rebind_count - info.snap.shader_rebind_count; - info.snap.vertices_count = info.render.vertices_count - info.snap.vertices_count; -} - -int RasterizerStorageGLES3::get_captured_render_info(VS::RenderInfo p_info) { - - switch (p_info) { - case VS::INFO_OBJECTS_IN_FRAME: { - - return info.snap.object_count; - } break; - case VS::INFO_VERTICES_IN_FRAME: { - - return info.snap.vertices_count; - } break; - case VS::INFO_MATERIAL_CHANGES_IN_FRAME: { - return info.snap.material_switch_count; - } break; - case VS::INFO_SHADER_CHANGES_IN_FRAME: { - return info.snap.shader_rebind_count; - } break; - case VS::INFO_SURFACE_CHANGES_IN_FRAME: { - return info.snap.surface_switch_count; - } break; - case VS::INFO_DRAW_CALLS_IN_FRAME: { - return info.snap.draw_call_count; - } break; - default: { - return get_render_info(p_info); - } - } -} - -int RasterizerStorageGLES3::get_render_info(VS::RenderInfo p_info) { - - switch (p_info) { - case VS::INFO_OBJECTS_IN_FRAME: - return info.render_final.object_count; - case VS::INFO_VERTICES_IN_FRAME: - return info.render_final.vertices_count; - case VS::INFO_MATERIAL_CHANGES_IN_FRAME: - return info.render_final.material_switch_count; - case VS::INFO_SHADER_CHANGES_IN_FRAME: - return info.render_final.shader_rebind_count; - case VS::INFO_SURFACE_CHANGES_IN_FRAME: - return info.render_final.surface_switch_count; - case VS::INFO_DRAW_CALLS_IN_FRAME: - return info.render_final.draw_call_count; - case VS::INFO_USAGE_VIDEO_MEM_TOTAL: - return 0; //no idea - case VS::INFO_VIDEO_MEM_USED: - return info.vertex_mem + info.texture_mem; - case VS::INFO_TEXTURE_MEM_USED: - return info.texture_mem; - case VS::INFO_VERTEX_MEM_USED: - return info.vertex_mem; - default: - return 0; //no idea either - } -} - -String RasterizerStorageGLES3::get_video_adapter_name() const { - - return (const char *)glGetString(GL_RENDERER); -} - -String RasterizerStorageGLES3::get_video_adapter_vendor() const { - - return (const char *)glGetString(GL_VENDOR); -} - -void RasterizerStorageGLES3::initialize() { - - RasterizerStorageGLES3::system_fbo = 0; - - //// extensions config - /// - - { - - int max_extensions = 0; - glGetIntegerv(GL_NUM_EXTENSIONS, &max_extensions); - for (int i = 0; i < max_extensions; i++) { - const GLubyte *s = glGetStringi(GL_EXTENSIONS, i); - if (!s) - break; - config.extensions.insert((const char *)s); - } - } - - config.shrink_textures_x2 = false; - config.use_fast_texture_filter = int(ProjectSettings::get_singleton()->get("rendering/quality/filters/use_nearest_mipmap_filter")); - config.use_anisotropic_filter = config.extensions.has("rendering/quality/filters/anisotropic_filter_level"); - - config.etc_supported = config.extensions.has("GL_OES_compressed_ETC1_RGB8_texture"); - config.latc_supported = config.extensions.has("GL_EXT_texture_compression_latc"); - config.bptc_supported = config.extensions.has("GL_ARB_texture_compression_bptc"); -#ifdef GLES_OVER_GL - config.etc2_supported = false; - config.s3tc_supported = true; - config.rgtc_supported = true; //RGTC - core since OpenGL version 3.0 - config.texture_float_linear_supported = true; - config.framebuffer_float_supported = true; - config.framebuffer_half_float_supported = true; - -#else - config.etc2_supported = true; - config.s3tc_supported = config.extensions.has("GL_EXT_texture_compression_dxt1") || config.extensions.has("GL_EXT_texture_compression_s3tc") || config.extensions.has("WEBGL_compressed_texture_s3tc"); - config.rgtc_supported = config.extensions.has("GL_EXT_texture_compression_rgtc") || config.extensions.has("GL_ARB_texture_compression_rgtc") || config.extensions.has("EXT_texture_compression_rgtc"); - config.texture_float_linear_supported = config.extensions.has("GL_OES_texture_float_linear"); - config.framebuffer_float_supported = config.extensions.has("GL_EXT_color_buffer_float"); - config.framebuffer_half_float_supported = config.extensions.has("GL_EXT_color_buffer_half_float") || config.framebuffer_float_supported; - -#endif - - config.pvrtc_supported = config.extensions.has("GL_IMG_texture_compression_pvrtc"); - config.srgb_decode_supported = config.extensions.has("GL_EXT_texture_sRGB_decode"); - - config.anisotropic_level = 1.0; - config.use_anisotropic_filter = config.extensions.has("GL_EXT_texture_filter_anisotropic"); - if (config.use_anisotropic_filter) { - glGetFloatv(_GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &config.anisotropic_level); - config.anisotropic_level = MIN(int(ProjectSettings::get_singleton()->get("rendering/quality/filters/anisotropic_filter_level")), config.anisotropic_level); - } - - frame.clear_request = false; - - shaders.copy.init(); - - { - //default textures - - glGenTextures(1, &resources.white_tex); - unsigned char whitetexdata[8 * 8 * 3]; - for (int i = 0; i < 8 * 8 * 3; i++) { - whitetexdata[i] = 255; - } - - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, resources.white_tex); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 8, 8, 0, GL_RGB, GL_UNSIGNED_BYTE, whitetexdata); - glGenerateMipmap(GL_TEXTURE_2D); - glBindTexture(GL_TEXTURE_2D, 0); - - glGenTextures(1, &resources.black_tex); - unsigned char blacktexdata[8 * 8 * 3]; - for (int i = 0; i < 8 * 8 * 3; i++) { - blacktexdata[i] = 0; - } - - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, resources.black_tex); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 8, 8, 0, GL_RGB, GL_UNSIGNED_BYTE, blacktexdata); - glGenerateMipmap(GL_TEXTURE_2D); - glBindTexture(GL_TEXTURE_2D, 0); - - glGenTextures(1, &resources.normal_tex); - unsigned char normaltexdata[8 * 8 * 3]; - for (int i = 0; i < 8 * 8 * 3; i += 3) { - normaltexdata[i + 0] = 128; - normaltexdata[i + 1] = 128; - normaltexdata[i + 2] = 255; - } - - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, resources.normal_tex); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 8, 8, 0, GL_RGB, GL_UNSIGNED_BYTE, normaltexdata); - glGenerateMipmap(GL_TEXTURE_2D); - glBindTexture(GL_TEXTURE_2D, 0); - - glGenTextures(1, &resources.aniso_tex); - unsigned char anisotexdata[8 * 8 * 3]; - for (int i = 0; i < 8 * 8 * 3; i += 3) { - anisotexdata[i + 0] = 255; - anisotexdata[i + 1] = 128; - anisotexdata[i + 2] = 0; - } - - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, resources.aniso_tex); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 8, 8, 0, GL_RGB, GL_UNSIGNED_BYTE, anisotexdata); - glGenerateMipmap(GL_TEXTURE_2D); - glBindTexture(GL_TEXTURE_2D, 0); - - glGenTextures(1, &resources.white_tex_3d); - - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_3D, resources.white_tex_3d); - glTexImage3D(GL_TEXTURE_3D, 0, GL_RGB, 2, 2, 2, 0, GL_RGB, GL_UNSIGNED_BYTE, whitetexdata); - - glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_BASE_LEVEL, 0); - glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAX_LEVEL, 0); - - glGenTextures(1, &resources.white_tex_array); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D_ARRAY, resources.white_tex_array); - glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGB, 8, 8, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); - glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 0, 8, 8, 1, GL_RGB, GL_UNSIGNED_BYTE, whitetexdata); - glGenerateMipmap(GL_TEXTURE_2D_ARRAY); - glBindTexture(GL_TEXTURE_2D, 0); - } - - glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &config.max_texture_image_units); - glGetIntegerv(GL_MAX_TEXTURE_SIZE, &config.max_texture_size); - - config.use_rgba_2d_shadows = !config.framebuffer_float_supported; - - //generic quadie for copying - - { - //quad buffers - - glGenBuffers(1, &resources.quadie); - glBindBuffer(GL_ARRAY_BUFFER, resources.quadie); - { - const float qv[16] = { - -1, - -1, - 0, - 0, - -1, - 1, - 0, - 1, - 1, - 1, - 1, - 1, - 1, - -1, - 1, - 0, - }; - - glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 16, qv, GL_STATIC_DRAW); - } - - glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind - - glGenVertexArrays(1, &resources.quadie_array); - glBindVertexArray(resources.quadie_array); - glBindBuffer(GL_ARRAY_BUFFER, resources.quadie); - glVertexAttribPointer(VS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 4, 0); - glEnableVertexAttribArray(0); - glVertexAttribPointer(VS::ARRAY_TEX_UV, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 4, CAST_INT_TO_UCHAR_PTR(8)); - glEnableVertexAttribArray(4); - glBindVertexArray(0); - glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind - } - - //generic quadie for copying without touching sky - - { - //transform feedback buffers - uint32_t xf_feedback_size = GLOBAL_DEF_RST("rendering/limits/buffers/blend_shape_max_buffer_size_kb", 4096); - ProjectSettings::get_singleton()->set_custom_property_info("rendering/limits/buffers/blend_shape_max_buffer_size_kb", PropertyInfo(Variant::INT, "rendering/limits/buffers/blend_shape_max_buffer_size_kb", PROPERTY_HINT_RANGE, "0,8192,1,or_greater")); - - for (int i = 0; i < 2; i++) { - - glGenBuffers(1, &resources.transform_feedback_buffers[i]); - glBindBuffer(GL_ARRAY_BUFFER, resources.transform_feedback_buffers[i]); - glBufferData(GL_ARRAY_BUFFER, xf_feedback_size * 1024, NULL, GL_STREAM_DRAW); - } - - shaders.blend_shapes.init(); - - glGenVertexArrays(1, &resources.transform_feedback_array); - } - - shaders.cubemap_filter.init(); - bool ggx_hq = GLOBAL_GET("rendering/quality/reflections/high_quality_ggx"); - shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::LOW_QUALITY, !ggx_hq); - shaders.particles.init(); - -#ifdef GLES_OVER_GL - glEnable(_EXT_TEXTURE_CUBE_MAP_SEAMLESS); -#endif - - frame.count = 0; - frame.delta = 0; - frame.current_rt = NULL; - config.keep_original_textures = false; - config.generate_wireframes = false; - config.use_texture_array_environment = GLOBAL_GET("rendering/quality/reflections/texture_array_reflections"); - - config.force_vertex_shading = GLOBAL_GET("rendering/quality/shading/force_vertex_shading"); - - String renderer = (const char *)glGetString(GL_RENDERER); - - config.use_depth_prepass = bool(GLOBAL_GET("rendering/quality/depth_prepass/enable")); - if (config.use_depth_prepass) { - - String vendors = GLOBAL_GET("rendering/quality/depth_prepass/disable_for_vendors"); - Vector<String> vendor_match = vendors.split(","); - for (int i = 0; i < vendor_match.size(); i++) { - String v = vendor_match[i].strip_edges(); - if (v == String()) - continue; - - if (renderer.findn(v) != -1) { - config.use_depth_prepass = false; - } - } - } -} - -void RasterizerStorageGLES3::finalize() { - - glDeleteTextures(1, &resources.white_tex); - glDeleteTextures(1, &resources.black_tex); - glDeleteTextures(1, &resources.normal_tex); -} - -void RasterizerStorageGLES3::update_dirty_resources() { - - update_dirty_multimeshes(); - update_dirty_skeletons(); - update_dirty_shaders(); - update_dirty_materials(); - update_particles(); -} - -RasterizerStorageGLES3::RasterizerStorageGLES3() { -} diff --git a/drivers/gles3/rasterizer_storage_gles3.h b/drivers/gles3/rasterizer_storage_gles3.h deleted file mode 100644 index bd853852fe..0000000000 --- a/drivers/gles3/rasterizer_storage_gles3.h +++ /dev/null @@ -1,1476 +0,0 @@ -/*************************************************************************/ -/* rasterizer_storage_gles3.h */ -/*************************************************************************/ -/* 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. */ -/*************************************************************************/ - -#ifndef RASTERIZERSTORAGEGLES3_H -#define RASTERIZERSTORAGEGLES3_H - -#include "core/self_list.h" -#include "servers/visual/rasterizer.h" -#include "servers/visual/shader_language.h" -#include "shader_compiler_gles3.h" -#include "shader_gles3.h" - -#include "shaders/blend_shape.glsl.gen.h" -#include "shaders/canvas.glsl.gen.h" -#include "shaders/copy.glsl.gen.h" -#include "shaders/cubemap_filter.glsl.gen.h" -#include "shaders/particles.glsl.gen.h" - -// WebGL 2.0 has no MapBufferRange/UnmapBuffer, but offers a non-ES style BufferSubData API instead. -#ifdef __EMSCRIPTEN__ -void glGetBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, GLvoid *data); -#endif - -class RasterizerCanvasGLES3; -class RasterizerSceneGLES3; - -#define _TEXTURE_SRGB_DECODE_EXT 0x8A48 -#define _DECODE_EXT 0x8A49 -#define _SKIP_DECODE_EXT 0x8A4A - -void glTexStorage2DCustom(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type); - -class RasterizerStorageGLES3 : public RasterizerStorage { -public: - RasterizerCanvasGLES3 *canvas; - RasterizerSceneGLES3 *scene; - static GLuint system_fbo; //on some devices, such as apple, screen is rendered to yet another fbo. - - enum RenderArchitecture { - RENDER_ARCH_MOBILE, - RENDER_ARCH_DESKTOP, - }; - - struct Config { - - bool shrink_textures_x2; - bool use_fast_texture_filter; - bool use_anisotropic_filter; - - bool s3tc_supported; - bool latc_supported; - bool rgtc_supported; - bool bptc_supported; - bool etc_supported; - bool etc2_supported; - bool pvrtc_supported; - - bool srgb_decode_supported; - - bool texture_float_linear_supported; - bool framebuffer_float_supported; - bool framebuffer_half_float_supported; - - bool use_rgba_2d_shadows; - - float anisotropic_level; - - int max_texture_image_units; - int max_texture_size; - - bool generate_wireframes; - - bool use_texture_array_environment; - - Set<String> extensions; - - bool keep_original_textures; - - bool use_depth_prepass; - bool force_vertex_shading; - } config; - - mutable struct Shaders { - - CopyShaderGLES3 copy; - - ShaderCompilerGLES3 compiler; - - CubemapFilterShaderGLES3 cubemap_filter; - - BlendShapeShaderGLES3 blend_shapes; - - ParticlesShaderGLES3 particles; - - ShaderCompilerGLES3::IdentifierActions actions_canvas; - ShaderCompilerGLES3::IdentifierActions actions_scene; - ShaderCompilerGLES3::IdentifierActions actions_particles; - } shaders; - - struct Resources { - - GLuint white_tex; - GLuint black_tex; - GLuint normal_tex; - GLuint aniso_tex; - - GLuint white_tex_3d; - GLuint white_tex_array; - - GLuint quadie; - GLuint quadie_array; - - GLuint transform_feedback_buffers[2]; - GLuint transform_feedback_array; - - } resources; - - struct Info { - - uint64_t texture_mem; - uint64_t vertex_mem; - - struct Render { - uint32_t object_count; - uint32_t draw_call_count; - uint32_t material_switch_count; - uint32_t surface_switch_count; - uint32_t shader_rebind_count; - uint32_t vertices_count; - - void reset() { - object_count = 0; - draw_call_count = 0; - material_switch_count = 0; - surface_switch_count = 0; - shader_rebind_count = 0; - vertices_count = 0; - } - } render, render_final, snap; - - Info() { - - texture_mem = 0; - vertex_mem = 0; - render.reset(); - render_final.reset(); - } - - } info; - - ///////////////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////DATA/////////////////////////////////////////////////// - ///////////////////////////////////////////////////////////////////////////////////////// - - struct Instantiable : public RID_Data { - - SelfList<RasterizerScene::InstanceBase>::List instance_list; - - _FORCE_INLINE_ void instance_change_notify(bool p_aabb, bool p_materials) { - - SelfList<RasterizerScene::InstanceBase> *instances = instance_list.first(); - while (instances) { - - instances->self()->base_changed(p_aabb, p_materials); - instances = instances->next(); - } - } - - _FORCE_INLINE_ void instance_remove_deps() { - SelfList<RasterizerScene::InstanceBase> *instances = instance_list.first(); - while (instances) { - - SelfList<RasterizerScene::InstanceBase> *next = instances->next(); - instances->self()->base_removed(); - instances = next; - } - } - - Instantiable() {} - virtual ~Instantiable() { - } - }; - - struct GeometryOwner : public Instantiable { - - virtual ~GeometryOwner() {} - }; - struct Geometry : Instantiable { - - enum Type { - GEOMETRY_INVALID, - GEOMETRY_SURFACE, - GEOMETRY_IMMEDIATE, - GEOMETRY_MULTISURFACE, - }; - - Type type; - RID material; - uint64_t last_pass; - uint32_t index; - - virtual void material_changed_notify() {} - - Geometry() { - last_pass = 0; - index = 0; - } - }; - - ///////////////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////API//////////////////////////////////////////////////// - ///////////////////////////////////////////////////////////////////////////////////////// - - /* TEXTURE API */ - - struct RenderTarget; - - struct Texture : public RID_Data { - - Texture *proxy; - Set<Texture *> proxy_owners; - - String path; - uint32_t flags; - int width, height, depth; - int alloc_width, alloc_height, alloc_depth; - Image::Format format; - VS::TextureType type; - - GLenum target; - GLenum gl_format_cache; - GLenum gl_internal_format_cache; - GLenum gl_type_cache; - int data_size; //original data size, useful for retrieving back - bool compressed; - bool srgb; - int total_data_size; - bool ignore_mipmaps; - - int mipmaps; - - bool is_npot_repeat_mipmap; - - bool active; - GLuint tex_id; - - bool using_srgb; - bool redraw_if_visible; - - uint16_t stored_cube_sides; - - RenderTarget *render_target; - - Vector<Ref<Image> > images; - - VisualServer::TextureDetectCallback detect_3d; - void *detect_3d_ud; - - VisualServer::TextureDetectCallback detect_srgb; - void *detect_srgb_ud; - - VisualServer::TextureDetectCallback detect_normal; - void *detect_normal_ud; - - Texture() : - proxy(NULL), - flags(0), - width(0), - height(0), - format(Image::FORMAT_L8), - type(VS::TEXTURE_TYPE_2D), - target(GL_TEXTURE_2D), - data_size(0), - compressed(false), - srgb(false), - total_data_size(0), - ignore_mipmaps(false), - mipmaps(0), - active(false), - tex_id(0), - using_srgb(false), - redraw_if_visible(false), - stored_cube_sides(0), - render_target(NULL), - detect_3d(NULL), - detect_3d_ud(NULL), - detect_srgb(NULL), - detect_srgb_ud(NULL), - detect_normal(NULL), - detect_normal_ud(NULL) { - } - - _ALWAYS_INLINE_ Texture *get_ptr() { - if (proxy) { - return proxy; //->get_ptr(); only one level of indirection, else not inlining possible. - } else { - return this; - } - } - - ~Texture() { - - if (tex_id != 0) { - - glDeleteTextures(1, &tex_id); - } - - for (Set<Texture *>::Element *E = proxy_owners.front(); E; E = E->next()) { - E->get()->proxy = NULL; - } - - if (proxy) { - proxy->proxy_owners.erase(this); - } - } - }; - - mutable RID_Owner<Texture> texture_owner; - - Ref<Image> _get_gl_image_and_format(const Ref<Image> &p_image, Image::Format p_format, uint32_t p_flags, Image::Format &r_real_format, GLenum &r_gl_format, GLenum &r_gl_internal_format, GLenum &r_gl_type, bool &r_compressed, bool &r_srgb, bool p_force_decompress) const; - - virtual RID texture_create(); - virtual void texture_allocate(RID p_texture, int p_width, int p_height, int p_depth_3d, Image::Format p_format, VS::TextureType p_type, uint32_t p_flags = VS::TEXTURE_FLAGS_DEFAULT); - virtual void texture_set_data(RID p_texture, const Ref<Image> &p_image, int p_layer = 0); - virtual void texture_set_data_partial(RID p_texture, const Ref<Image> &p_image, int src_x, int src_y, int src_w, int src_h, int dst_x, int dst_y, int p_dst_mip, int p_layer = 0); - virtual Ref<Image> texture_get_data(RID p_texture, int p_layer = 0) const; - virtual void texture_set_flags(RID p_texture, uint32_t p_flags); - virtual uint32_t texture_get_flags(RID p_texture) const; - virtual Image::Format texture_get_format(RID p_texture) const; - virtual VS::TextureType texture_get_type(RID p_texture) const; - virtual uint32_t texture_get_texid(RID p_texture) const; - virtual uint32_t texture_get_width(RID p_texture) const; - virtual uint32_t texture_get_height(RID p_texture) const; - virtual uint32_t texture_get_depth(RID p_texture) const; - virtual void texture_set_size_override(RID p_texture, int p_width, int p_height, int p_depth); - virtual void texture_bind(RID p_texture, uint32_t p_texture_no); - - virtual void texture_set_path(RID p_texture, const String &p_path); - virtual String texture_get_path(RID p_texture) const; - - virtual void texture_set_shrink_all_x2_on_set_data(bool p_enable); - - virtual void texture_debug_usage(List<VS::TextureInfo> *r_info); - - virtual RID texture_create_radiance_cubemap(RID p_source, int p_resolution = -1) const; - - virtual void textures_keep_original(bool p_enable); - - virtual void texture_set_detect_3d_callback(RID p_texture, VisualServer::TextureDetectCallback p_callback, void *p_userdata); - virtual void texture_set_detect_srgb_callback(RID p_texture, VisualServer::TextureDetectCallback p_callback, void *p_userdata); - virtual void texture_set_detect_normal_callback(RID p_texture, VisualServer::TextureDetectCallback p_callback, void *p_userdata); - - virtual void texture_set_proxy(RID p_texture, RID p_proxy); - virtual Size2 texture_size_with_proxy(RID p_texture) const; - - virtual void texture_set_force_redraw_if_visible(RID p_texture, bool p_enable); - - /* SKY API */ - - struct Sky : public RID_Data { - - RID panorama; - GLuint radiance; - GLuint irradiance; - int radiance_size; - }; - - mutable RID_Owner<Sky> sky_owner; - - virtual RID sky_create(); - virtual void sky_set_texture(RID p_sky, RID p_panorama, int p_radiance_size); - - /* SHADER API */ - - struct Material; - - struct Shader : public RID_Data { - - RID self; - - VS::ShaderMode mode; - ShaderGLES3 *shader; - String code; - SelfList<Material>::List materials; - - Map<StringName, ShaderLanguage::ShaderNode::Uniform> uniforms; - Vector<uint32_t> ubo_offsets; - uint32_t ubo_size; - - uint32_t texture_count; - - uint32_t custom_code_id; - uint32_t version; - - SelfList<Shader> dirty_list; - - Map<StringName, RID> default_textures; - - Vector<ShaderLanguage::DataType> texture_types; - Vector<ShaderLanguage::ShaderNode::Uniform::Hint> texture_hints; - - bool valid; - - String path; - - struct CanvasItem { - - enum BlendMode { - BLEND_MODE_MIX, - BLEND_MODE_ADD, - BLEND_MODE_SUB, - BLEND_MODE_MUL, - BLEND_MODE_PMALPHA, - BLEND_MODE_DISABLED, - }; - - int blend_mode; - - enum LightMode { - LIGHT_MODE_NORMAL, - LIGHT_MODE_UNSHADED, - LIGHT_MODE_LIGHT_ONLY - }; - - int light_mode; - - bool uses_screen_texture; - bool uses_screen_uv; - bool uses_time; - - } canvas_item; - - struct Spatial { - - enum BlendMode { - BLEND_MODE_MIX, - BLEND_MODE_ADD, - BLEND_MODE_SUB, - BLEND_MODE_MUL, - }; - - int blend_mode; - - enum DepthDrawMode { - DEPTH_DRAW_OPAQUE, - DEPTH_DRAW_ALWAYS, - DEPTH_DRAW_NEVER, - DEPTH_DRAW_ALPHA_PREPASS, - }; - - int depth_draw_mode; - - enum CullMode { - CULL_MODE_FRONT, - CULL_MODE_BACK, - CULL_MODE_DISABLED, - }; - - int cull_mode; - - bool uses_alpha; - bool uses_alpha_scissor; - bool unshaded; - bool no_depth_test; - bool uses_vertex; - bool uses_discard; - bool uses_sss; - bool uses_screen_texture; - bool uses_depth_texture; - bool uses_time; - bool writes_modelview_or_projection; - bool uses_vertex_lighting; - bool uses_world_coordinates; - - } spatial; - - struct Particles { - - } particles; - - bool uses_vertex_time; - bool uses_fragment_time; - - Shader() : - dirty_list(this) { - - shader = NULL; - ubo_size = 0; - valid = false; - custom_code_id = 0; - version = 1; - } - }; - - mutable SelfList<Shader>::List _shader_dirty_list; - void _shader_make_dirty(Shader *p_shader); - - mutable RID_Owner<Shader> shader_owner; - - virtual RID shader_create(); - - virtual void shader_set_code(RID p_shader, const String &p_code); - virtual String shader_get_code(RID p_shader) const; - virtual void shader_get_param_list(RID p_shader, List<PropertyInfo> *p_param_list) const; - - virtual void shader_set_default_texture_param(RID p_shader, const StringName &p_name, RID p_texture); - virtual RID shader_get_default_texture_param(RID p_shader, const StringName &p_name) const; - - void _update_shader(Shader *p_shader) const; - - void update_dirty_shaders(); - - /* COMMON MATERIAL API */ - - struct Material : public RID_Data { - - Shader *shader; - GLuint ubo_id; - uint32_t ubo_size; - Map<StringName, Variant> params; - SelfList<Material> list; - SelfList<Material> dirty_list; - Vector<bool> texture_is_3d; - Vector<RID> textures; - float line_width; - int render_priority; - - RID next_pass; - - uint32_t index; - uint64_t last_pass; - - Map<Geometry *, int> geometry_owners; - Map<RasterizerScene::InstanceBase *, int> instance_owners; - - bool can_cast_shadow_cache; - bool is_animated_cache; - - Material() : - shader(NULL), - ubo_id(0), - ubo_size(0), - list(this), - dirty_list(this), - line_width(1.0), - render_priority(0), - last_pass(0), - can_cast_shadow_cache(false), - is_animated_cache(false) { - } - }; - - mutable SelfList<Material>::List _material_dirty_list; - void _material_make_dirty(Material *p_material) const; - void _material_add_geometry(RID p_material, Geometry *p_geometry); - void _material_remove_geometry(RID p_material, Geometry *p_geometry); - - mutable RID_Owner<Material> material_owner; - - virtual RID material_create(); - - virtual void material_set_shader(RID p_material, RID p_shader); - virtual RID material_get_shader(RID p_material) const; - - virtual void material_set_param(RID p_material, const StringName &p_param, const Variant &p_value); - virtual Variant material_get_param(RID p_material, const StringName &p_param) const; - virtual Variant material_get_param_default(RID p_material, const StringName &p_param) const; - - virtual void material_set_line_width(RID p_material, float p_width); - virtual void material_set_next_pass(RID p_material, RID p_next_material); - - virtual bool material_is_animated(RID p_material); - virtual bool material_casts_shadows(RID p_material); - - virtual void material_add_instance_owner(RID p_material, RasterizerScene::InstanceBase *p_instance); - virtual void material_remove_instance_owner(RID p_material, RasterizerScene::InstanceBase *p_instance); - - virtual void material_set_render_priority(RID p_material, int priority); - - void _update_material(Material *material); - - void update_dirty_materials(); - - /* MESH API */ - - struct Mesh; - struct Surface : public Geometry { - - struct Attrib { - - bool enabled; - bool integer; - GLuint index; - GLint size; - GLenum type; - GLboolean normalized; - GLsizei stride; - uint32_t offset; - }; - - Attrib attribs[VS::ARRAY_MAX]; - - Mesh *mesh; - uint32_t format; - - GLuint array_id; - GLuint instancing_array_id; - GLuint vertex_id; - GLuint index_id; - - GLuint index_wireframe_id; - GLuint array_wireframe_id; - GLuint instancing_array_wireframe_id; - int index_wireframe_len; - - Vector<AABB> skeleton_bone_aabb; - Vector<bool> skeleton_bone_used; - - //bool packed; - - struct BlendShape { - GLuint vertex_id; - GLuint array_id; - }; - - Vector<BlendShape> blend_shapes; - - AABB aabb; - - int array_len; - int index_array_len; - int max_bone; - - int array_byte_size; - int index_array_byte_size; - - VS::PrimitiveType primitive; - - bool active; - - virtual void material_changed_notify() { - mesh->instance_change_notify(false, true); - mesh->update_multimeshes(); - } - - int total_data_size; - - Surface() : - mesh(NULL), - format(0), - array_id(0), - vertex_id(0), - index_id(0), - index_wireframe_id(0), - array_wireframe_id(0), - instancing_array_wireframe_id(0), - index_wireframe_len(0), - array_len(0), - index_array_len(0), - array_byte_size(0), - index_array_byte_size(0), - primitive(VS::PRIMITIVE_POINTS), - active(false), - total_data_size(0) { - type = GEOMETRY_SURFACE; - } - - ~Surface() { - } - }; - - struct MultiMesh; - - struct Mesh : public GeometryOwner { - - bool active; - Vector<Surface *> surfaces; - int blend_shape_count; - VS::BlendShapeMode blend_shape_mode; - AABB custom_aabb; - mutable uint64_t last_pass; - SelfList<MultiMesh>::List multimeshes; - _FORCE_INLINE_ void update_multimeshes() { - - SelfList<MultiMesh> *mm = multimeshes.first(); - while (mm) { - mm->self()->instance_change_notify(false, true); - mm = mm->next(); - } - } - - Mesh() : - active(false), - blend_shape_count(0), - blend_shape_mode(VS::BLEND_SHAPE_MODE_NORMALIZED), - last_pass(0) { - } - }; - - mutable RID_Owner<Mesh> mesh_owner; - - virtual RID mesh_create(); - - virtual void mesh_add_surface(RID p_mesh, uint32_t p_format, VS::PrimitiveType p_primitive, const PoolVector<uint8_t> &p_array, int p_vertex_count, const PoolVector<uint8_t> &p_index_array, int p_index_count, const AABB &p_aabb, const Vector<PoolVector<uint8_t> > &p_blend_shapes = Vector<PoolVector<uint8_t> >(), const Vector<AABB> &p_bone_aabbs = Vector<AABB>()); - - virtual void mesh_set_blend_shape_count(RID p_mesh, int p_amount); - virtual int mesh_get_blend_shape_count(RID p_mesh) const; - - virtual void mesh_set_blend_shape_mode(RID p_mesh, VS::BlendShapeMode p_mode); - virtual VS::BlendShapeMode mesh_get_blend_shape_mode(RID p_mesh) const; - - virtual void mesh_surface_update_region(RID p_mesh, int p_surface, int p_offset, const PoolVector<uint8_t> &p_data); - - virtual void mesh_surface_set_material(RID p_mesh, int p_surface, RID p_material); - virtual RID mesh_surface_get_material(RID p_mesh, int p_surface) const; - - virtual int mesh_surface_get_array_len(RID p_mesh, int p_surface) const; - virtual int mesh_surface_get_array_index_len(RID p_mesh, int p_surface) const; - - virtual PoolVector<uint8_t> mesh_surface_get_array(RID p_mesh, int p_surface) const; - virtual PoolVector<uint8_t> mesh_surface_get_index_array(RID p_mesh, int p_surface) const; - - virtual uint32_t mesh_surface_get_format(RID p_mesh, int p_surface) const; - virtual VS::PrimitiveType mesh_surface_get_primitive_type(RID p_mesh, int p_surface) const; - - virtual AABB mesh_surface_get_aabb(RID p_mesh, int p_surface) const; - virtual Vector<PoolVector<uint8_t> > mesh_surface_get_blend_shapes(RID p_mesh, int p_surface) const; - virtual Vector<AABB> mesh_surface_get_skeleton_aabb(RID p_mesh, int p_surface) const; - - virtual void mesh_remove_surface(RID p_mesh, int p_surface); - virtual int mesh_get_surface_count(RID p_mesh) const; - - virtual void mesh_set_custom_aabb(RID p_mesh, const AABB &p_aabb); - virtual AABB mesh_get_custom_aabb(RID p_mesh) const; - - virtual AABB mesh_get_aabb(RID p_mesh, RID p_skeleton) const; - virtual void mesh_clear(RID p_mesh); - - void mesh_render_blend_shapes(Surface *s, const float *p_weights); - - /* MULTIMESH API */ - - struct MultiMesh : public GeometryOwner { - RID mesh; - int size; - VS::MultimeshTransformFormat transform_format; - VS::MultimeshColorFormat color_format; - VS::MultimeshCustomDataFormat custom_data_format; - Vector<float> data; - AABB aabb; - SelfList<MultiMesh> update_list; - SelfList<MultiMesh> mesh_list; - GLuint buffer; - int visible_instances; - - int xform_floats; - int color_floats; - int custom_data_floats; - - bool dirty_aabb; - bool dirty_data; - - MultiMesh() : - size(0), - transform_format(VS::MULTIMESH_TRANSFORM_2D), - color_format(VS::MULTIMESH_COLOR_NONE), - custom_data_format(VS::MULTIMESH_CUSTOM_DATA_NONE), - update_list(this), - mesh_list(this), - buffer(0), - visible_instances(-1), - xform_floats(0), - color_floats(0), - custom_data_floats(0), - dirty_aabb(true), - dirty_data(true) { - } - }; - - mutable RID_Owner<MultiMesh> multimesh_owner; - - SelfList<MultiMesh>::List multimesh_update_list; - - void update_dirty_multimeshes(); - - virtual RID multimesh_create(); - - virtual void multimesh_allocate(RID p_multimesh, int p_instances, VS::MultimeshTransformFormat p_transform_format, VS::MultimeshColorFormat p_color_format, VS::MultimeshCustomDataFormat p_data_format = VS::MULTIMESH_CUSTOM_DATA_NONE); - virtual int multimesh_get_instance_count(RID p_multimesh) const; - - virtual void multimesh_set_mesh(RID p_multimesh, RID p_mesh); - virtual void multimesh_instance_set_transform(RID p_multimesh, int p_index, const Transform &p_transform); - virtual void multimesh_instance_set_transform_2d(RID p_multimesh, int p_index, const Transform2D &p_transform); - virtual void multimesh_instance_set_color(RID p_multimesh, int p_index, const Color &p_color); - virtual void multimesh_instance_set_custom_data(RID p_multimesh, int p_index, const Color &p_custom_data); - - virtual RID multimesh_get_mesh(RID p_multimesh) const; - - virtual Transform multimesh_instance_get_transform(RID p_multimesh, int p_index) const; - virtual Transform2D multimesh_instance_get_transform_2d(RID p_multimesh, int p_index) const; - virtual Color multimesh_instance_get_color(RID p_multimesh, int p_index) const; - virtual Color multimesh_instance_get_custom_data(RID p_multimesh, int p_index) const; - - virtual void multimesh_set_as_bulk_array(RID p_multimesh, const PoolVector<float> &p_array); - - virtual void multimesh_set_visible_instances(RID p_multimesh, int p_visible); - virtual int multimesh_get_visible_instances(RID p_multimesh) const; - - virtual AABB multimesh_get_aabb(RID p_multimesh) const; - - /* IMMEDIATE API */ - - struct Immediate : public Geometry { - - struct Chunk { - - RID texture; - VS::PrimitiveType primitive; - Vector<Vector3> vertices; - Vector<Vector3> normals; - Vector<Plane> tangents; - Vector<Color> colors; - Vector<Vector2> uvs; - Vector<Vector2> uvs2; - }; - - List<Chunk> chunks; - bool building; - int mask; - AABB aabb; - - Immediate() { - type = GEOMETRY_IMMEDIATE; - building = false; - } - }; - - Vector3 chunk_vertex; - Vector3 chunk_normal; - Plane chunk_tangent; - Color chunk_color; - Vector2 chunk_uv; - Vector2 chunk_uv2; - - mutable RID_Owner<Immediate> immediate_owner; - - virtual RID immediate_create(); - virtual void immediate_begin(RID p_immediate, VS::PrimitiveType p_primitive, RID p_texture = RID()); - virtual void immediate_vertex(RID p_immediate, const Vector3 &p_vertex); - virtual void immediate_normal(RID p_immediate, const Vector3 &p_normal); - virtual void immediate_tangent(RID p_immediate, const Plane &p_tangent); - virtual void immediate_color(RID p_immediate, const Color &p_color); - virtual void immediate_uv(RID p_immediate, const Vector2 &tex_uv); - virtual void immediate_uv2(RID p_immediate, const Vector2 &tex_uv); - virtual void immediate_end(RID p_immediate); - virtual void immediate_clear(RID p_immediate); - virtual void immediate_set_material(RID p_immediate, RID p_material); - virtual RID immediate_get_material(RID p_immediate) const; - virtual AABB immediate_get_aabb(RID p_immediate) const; - - /* SKELETON API */ - - struct Skeleton : RID_Data { - bool use_2d; - int size; - Vector<float> skel_texture; - GLuint texture; - SelfList<Skeleton> update_list; - Set<RasterizerScene::InstanceBase *> instances; //instances using skeleton - Transform2D base_transform_2d; - - Skeleton() : - use_2d(false), - size(0), - texture(0), - update_list(this) { - } - }; - - mutable RID_Owner<Skeleton> skeleton_owner; - - SelfList<Skeleton>::List skeleton_update_list; - - void update_dirty_skeletons(); - - virtual RID skeleton_create(); - virtual void skeleton_allocate(RID p_skeleton, int p_bones, bool p_2d_skeleton = false); - virtual int skeleton_get_bone_count(RID p_skeleton) const; - virtual void skeleton_bone_set_transform(RID p_skeleton, int p_bone, const Transform &p_transform); - virtual Transform skeleton_bone_get_transform(RID p_skeleton, int p_bone) const; - virtual void skeleton_bone_set_transform_2d(RID p_skeleton, int p_bone, const Transform2D &p_transform); - virtual Transform2D skeleton_bone_get_transform_2d(RID p_skeleton, int p_bone) const; - virtual void skeleton_set_base_transform_2d(RID p_skeleton, const Transform2D &p_base_transform); - - /* Light API */ - - struct Light : Instantiable { - - VS::LightType type; - float param[VS::LIGHT_PARAM_MAX]; - Color color; - Color shadow_color; - RID projector; - bool shadow; - bool negative; - bool reverse_cull; - bool use_gi; - uint32_t cull_mask; - VS::LightOmniShadowMode omni_shadow_mode; - VS::LightOmniShadowDetail omni_shadow_detail; - VS::LightDirectionalShadowMode directional_shadow_mode; - VS::LightDirectionalShadowDepthRangeMode directional_range_mode; - bool directional_blend_splits; - uint64_t version; - }; - - mutable RID_Owner<Light> light_owner; - - virtual RID light_create(VS::LightType p_type); - - virtual void light_set_color(RID p_light, const Color &p_color); - virtual void light_set_param(RID p_light, VS::LightParam p_param, float p_value); - virtual void light_set_shadow(RID p_light, bool p_enabled); - virtual void light_set_shadow_color(RID p_light, const Color &p_color); - virtual void light_set_projector(RID p_light, RID p_texture); - virtual void light_set_negative(RID p_light, bool p_enable); - virtual void light_set_cull_mask(RID p_light, uint32_t p_mask); - virtual void light_set_reverse_cull_face_mode(RID p_light, bool p_enabled); - virtual void light_set_use_gi(RID p_light, bool p_enabled); - - virtual void light_omni_set_shadow_mode(RID p_light, VS::LightOmniShadowMode p_mode); - virtual void light_omni_set_shadow_detail(RID p_light, VS::LightOmniShadowDetail p_detail); - - virtual void light_directional_set_shadow_mode(RID p_light, VS::LightDirectionalShadowMode p_mode); - virtual void light_directional_set_blend_splits(RID p_light, bool p_enable); - virtual bool light_directional_get_blend_splits(RID p_light) const; - - virtual VS::LightDirectionalShadowMode light_directional_get_shadow_mode(RID p_light); - virtual VS::LightOmniShadowMode light_omni_get_shadow_mode(RID p_light); - - virtual void light_directional_set_shadow_depth_range_mode(RID p_light, VS::LightDirectionalShadowDepthRangeMode p_range_mode); - virtual VS::LightDirectionalShadowDepthRangeMode light_directional_get_shadow_depth_range_mode(RID p_light) const; - - virtual bool light_has_shadow(RID p_light) const; - - virtual VS::LightType light_get_type(RID p_light) const; - virtual float light_get_param(RID p_light, VS::LightParam p_param); - virtual Color light_get_color(RID p_light); - virtual bool light_get_use_gi(RID p_light); - - virtual AABB light_get_aabb(RID p_light) const; - virtual uint64_t light_get_version(RID p_light) const; - - /* PROBE API */ - - struct ReflectionProbe : Instantiable { - - VS::ReflectionProbeUpdateMode update_mode; - float intensity; - Color interior_ambient; - float interior_ambient_energy; - float interior_ambient_probe_contrib; - float max_distance; - Vector3 extents; - Vector3 origin_offset; - bool interior; - bool box_projection; - bool enable_shadows; - uint32_t cull_mask; - }; - - mutable RID_Owner<ReflectionProbe> reflection_probe_owner; - - virtual RID reflection_probe_create(); - - virtual void reflection_probe_set_update_mode(RID p_probe, VS::ReflectionProbeUpdateMode p_mode); - virtual void reflection_probe_set_intensity(RID p_probe, float p_intensity); - virtual void reflection_probe_set_interior_ambient(RID p_probe, const Color &p_ambient); - virtual void reflection_probe_set_interior_ambient_energy(RID p_probe, float p_energy); - virtual void reflection_probe_set_interior_ambient_probe_contribution(RID p_probe, float p_contrib); - virtual void reflection_probe_set_max_distance(RID p_probe, float p_distance); - virtual void reflection_probe_set_extents(RID p_probe, const Vector3 &p_extents); - virtual void reflection_probe_set_origin_offset(RID p_probe, const Vector3 &p_offset); - virtual void reflection_probe_set_as_interior(RID p_probe, bool p_enable); - virtual void reflection_probe_set_enable_box_projection(RID p_probe, bool p_enable); - virtual void reflection_probe_set_enable_shadows(RID p_probe, bool p_enable); - virtual void reflection_probe_set_cull_mask(RID p_probe, uint32_t p_layers); - virtual void reflection_probe_set_resolution(RID p_probe, int p_resolution); - - virtual AABB reflection_probe_get_aabb(RID p_probe) const; - virtual VS::ReflectionProbeUpdateMode reflection_probe_get_update_mode(RID p_probe) const; - virtual uint32_t reflection_probe_get_cull_mask(RID p_probe) const; - - virtual Vector3 reflection_probe_get_extents(RID p_probe) const; - virtual Vector3 reflection_probe_get_origin_offset(RID p_probe) const; - virtual float reflection_probe_get_origin_max_distance(RID p_probe) const; - virtual bool reflection_probe_renders_shadows(RID p_probe) const; - - /* GI PROBE API */ - - struct GIProbe : public Instantiable { - - AABB bounds; - Transform to_cell; - float cell_size; - - int dynamic_range; - float energy; - float bias; - float normal_bias; - float propagation; - bool interior; - bool compress; - - uint32_t version; - - PoolVector<int> dynamic_data; - }; - - mutable RID_Owner<GIProbe> gi_probe_owner; - - virtual RID gi_probe_create(); - - virtual void gi_probe_set_bounds(RID p_probe, const AABB &p_bounds); - virtual AABB gi_probe_get_bounds(RID p_probe) const; - - virtual void gi_probe_set_cell_size(RID p_probe, float p_size); - virtual float gi_probe_get_cell_size(RID p_probe) const; - - virtual void gi_probe_set_to_cell_xform(RID p_probe, const Transform &p_xform); - virtual Transform gi_probe_get_to_cell_xform(RID p_probe) const; - - virtual void gi_probe_set_dynamic_data(RID p_probe, const PoolVector<int> &p_data); - virtual PoolVector<int> gi_probe_get_dynamic_data(RID p_probe) const; - - virtual void gi_probe_set_dynamic_range(RID p_probe, int p_range); - virtual int gi_probe_get_dynamic_range(RID p_probe) const; - - virtual void gi_probe_set_energy(RID p_probe, float p_range); - virtual float gi_probe_get_energy(RID p_probe) const; - - virtual void gi_probe_set_bias(RID p_probe, float p_range); - virtual float gi_probe_get_bias(RID p_probe) const; - - virtual void gi_probe_set_normal_bias(RID p_probe, float p_range); - virtual float gi_probe_get_normal_bias(RID p_probe) const; - - virtual void gi_probe_set_propagation(RID p_probe, float p_range); - virtual float gi_probe_get_propagation(RID p_probe) const; - - virtual void gi_probe_set_interior(RID p_probe, bool p_enable); - virtual bool gi_probe_is_interior(RID p_probe) const; - - virtual void gi_probe_set_compress(RID p_probe, bool p_enable); - virtual bool gi_probe_is_compressed(RID p_probe) const; - - virtual uint32_t gi_probe_get_version(RID p_probe); - - struct GIProbeData : public RID_Data { - - int width; - int height; - int depth; - int levels; - GLuint tex_id; - GIProbeCompression compression; - - GIProbeData() { - } - }; - - mutable RID_Owner<GIProbeData> gi_probe_data_owner; - - virtual GIProbeCompression gi_probe_get_dynamic_data_get_preferred_compression() const; - virtual RID gi_probe_dynamic_data_create(int p_width, int p_height, int p_depth, GIProbeCompression p_compression); - virtual void gi_probe_dynamic_data_update(RID p_gi_probe_data, int p_depth_slice, int p_slice_count, int p_mipmap, const void *p_data); - - /* LIGHTMAP CAPTURE */ - - virtual RID lightmap_capture_create(); - virtual void lightmap_capture_set_bounds(RID p_capture, const AABB &p_bounds); - virtual AABB lightmap_capture_get_bounds(RID p_capture) const; - virtual void lightmap_capture_set_octree(RID p_capture, const PoolVector<uint8_t> &p_octree); - virtual PoolVector<uint8_t> lightmap_capture_get_octree(RID p_capture) const; - virtual void lightmap_capture_set_octree_cell_transform(RID p_capture, const Transform &p_xform); - virtual Transform lightmap_capture_get_octree_cell_transform(RID p_capture) const; - virtual void lightmap_capture_set_octree_cell_subdiv(RID p_capture, int p_subdiv); - virtual int lightmap_capture_get_octree_cell_subdiv(RID p_capture) const; - - virtual void lightmap_capture_set_energy(RID p_capture, float p_energy); - virtual float lightmap_capture_get_energy(RID p_capture) const; - - virtual const PoolVector<LightmapCaptureOctree> *lightmap_capture_get_octree_ptr(RID p_capture) const; - - struct LightmapCapture : public Instantiable { - - PoolVector<LightmapCaptureOctree> octree; - AABB bounds; - Transform cell_xform; - int cell_subdiv; - float energy; - LightmapCapture() { - energy = 1.0; - cell_subdiv = 1; - } - }; - - mutable RID_Owner<LightmapCapture> lightmap_capture_data_owner; - - /* PARTICLES */ - - struct Particles : public GeometryOwner { - - bool inactive; - float inactive_time; - bool emitting; - bool one_shot; - int amount; - float lifetime; - float pre_process_time; - float explosiveness; - float randomness; - bool restart_request; - AABB custom_aabb; - bool use_local_coords; - RID process_material; - - VS::ParticlesDrawOrder draw_order; - - Vector<RID> draw_passes; - - GLuint particle_buffers[2]; - GLuint particle_vaos[2]; - - GLuint particle_buffer_histories[2]; - GLuint particle_vao_histories[2]; - bool particle_valid_histories[2]; - bool histories_enabled; - - SelfList<Particles> particle_element; - - float phase; - float prev_phase; - uint64_t prev_ticks; - uint32_t random_seed; - - uint32_t cycle_number; - - float speed_scale; - - int fixed_fps; - bool fractional_delta; - float frame_remainder; - - bool clear; - - Transform emission_transform; - - Particles() : - inactive(true), - inactive_time(0.0), - emitting(false), - one_shot(false), - amount(0), - lifetime(1.0), - pre_process_time(0.0), - explosiveness(0.0), - randomness(0.0), - restart_request(false), - custom_aabb(AABB(Vector3(-4, -4, -4), Vector3(8, 8, 8))), - use_local_coords(true), - draw_order(VS::PARTICLES_DRAW_ORDER_INDEX), - histories_enabled(false), - particle_element(this), - prev_ticks(0), - random_seed(0), - cycle_number(0), - speed_scale(1.0), - fixed_fps(0), - fractional_delta(false), - frame_remainder(0), - clear(true) { - particle_buffers[0] = 0; - particle_buffers[1] = 0; - glGenBuffers(2, particle_buffers); - glGenVertexArrays(2, particle_vaos); - } - - ~Particles() { - - glDeleteBuffers(2, particle_buffers); - glDeleteVertexArrays(2, particle_vaos); - if (histories_enabled) { - glDeleteBuffers(2, particle_buffer_histories); - glDeleteVertexArrays(2, particle_vao_histories); - } - } - }; - - SelfList<Particles>::List particle_update_list; - - void update_particles(); - - mutable RID_Owner<Particles> particles_owner; - - virtual RID particles_create(); - - virtual void particles_set_emitting(RID p_particles, bool p_emitting); - virtual bool particles_get_emitting(RID p_particles); - virtual void particles_set_amount(RID p_particles, int p_amount); - virtual void particles_set_lifetime(RID p_particles, float p_lifetime); - virtual void particles_set_one_shot(RID p_particles, bool p_one_shot); - virtual void particles_set_pre_process_time(RID p_particles, float p_time); - virtual void particles_set_explosiveness_ratio(RID p_particles, float p_ratio); - virtual void particles_set_randomness_ratio(RID p_particles, float p_ratio); - virtual void particles_set_custom_aabb(RID p_particles, const AABB &p_aabb); - virtual void particles_set_speed_scale(RID p_particles, float p_scale); - virtual void particles_set_use_local_coordinates(RID p_particles, bool p_enable); - virtual void particles_set_process_material(RID p_particles, RID p_material); - virtual void particles_set_fixed_fps(RID p_particles, int p_fps); - virtual void particles_set_fractional_delta(RID p_particles, bool p_enable); - virtual void particles_restart(RID p_particles); - - virtual void particles_set_draw_order(RID p_particles, VS::ParticlesDrawOrder p_order); - - virtual void particles_set_draw_passes(RID p_particles, int p_passes); - virtual void particles_set_draw_pass_mesh(RID p_particles, int p_pass, RID p_mesh); - - virtual void particles_request_process(RID p_particles); - virtual AABB particles_get_current_aabb(RID p_particles); - virtual AABB particles_get_aabb(RID p_particles) const; - - virtual void _particles_update_histories(Particles *particles); - - virtual void particles_set_emission_transform(RID p_particles, const Transform &p_transform); - void _particles_process(Particles *p_particles, float p_delta); - - virtual int particles_get_draw_passes(RID p_particles) const; - virtual RID particles_get_draw_pass_mesh(RID p_particles, int p_pass) const; - - virtual bool particles_is_inactive(RID p_particles) const; - - /* INSTANCE */ - - virtual void instance_add_skeleton(RID p_skeleton, RasterizerScene::InstanceBase *p_instance); - virtual void instance_remove_skeleton(RID p_skeleton, RasterizerScene::InstanceBase *p_instance); - - virtual void instance_add_dependency(RID p_base, RasterizerScene::InstanceBase *p_instance); - virtual void instance_remove_dependency(RID p_base, RasterizerScene::InstanceBase *p_instance); - - /* RENDER TARGET */ - - struct RenderTarget : public RID_Data { - - GLuint fbo; - GLuint color; - GLuint depth; - - struct Buffers { - - bool active; - bool effects_active; - GLuint fbo; - GLuint depth; - GLuint specular; - GLuint diffuse; - GLuint normal_rough; - GLuint sss; - - GLuint effect_fbo; - GLuint effect; - - } buffers; - - struct Effects { - - struct MipMaps { - - struct Size { - GLuint fbo; - int width; - int height; - }; - - Vector<Size> sizes; - GLuint color; - int levels; - - MipMaps() : - color(0), - levels(0) { - } - }; - - MipMaps mip_maps[2]; //first mipmap chain starts from full-screen - //GLuint depth2; //depth for the second mipmap chain, in case of desiring upsampling - - struct SSAO { - GLuint blur_fbo[2]; // blur fbo - GLuint blur_red[2]; // 8 bits red buffer - - GLuint linear_depth; - - Vector<GLuint> depth_mipmap_fbos; //fbos for depth mipmapsla ver - - SSAO() : - linear_depth(0) { - blur_fbo[0] = 0; - blur_fbo[1] = 0; - } - } ssao; - - Effects() {} - - } effects; - - struct Exposure { - GLuint fbo; - GLuint color; - - Exposure() : - fbo(0) {} - } exposure; - - // External FBO to render our final result to (mostly used for ARVR) - struct External { - GLuint fbo; - RID texture; - - External() : - fbo(0) {} - } external; - - uint64_t last_exposure_tick; - - int width, height; - - bool flags[RENDER_TARGET_FLAG_MAX]; - - bool used_in_frame; - VS::ViewportMSAA msaa; - - RID texture; - - RenderTarget() : - fbo(0), - depth(0), - last_exposure_tick(0), - width(0), - height(0), - used_in_frame(false), - msaa(VS::VIEWPORT_MSAA_DISABLED) { - exposure.fbo = 0; - buffers.fbo = 0; - external.fbo = 0; - for (int i = 0; i < RENDER_TARGET_FLAG_MAX; i++) { - flags[i] = false; - } - flags[RENDER_TARGET_HDR] = true; - buffers.active = false; - buffers.effects_active = false; - } - }; - - mutable RID_Owner<RenderTarget> render_target_owner; - - void _render_target_clear(RenderTarget *rt); - void _render_target_allocate(RenderTarget *rt); - - virtual RID render_target_create(); - 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 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); - virtual void render_target_clear_used(RID p_render_target); - virtual void render_target_set_msaa(RID p_render_target, VS::ViewportMSAA p_msaa); - - /* CANVAS SHADOW */ - - struct CanvasLightShadow : public RID_Data { - - int size; - int height; - GLuint fbo; - GLuint depth; - GLuint distance; //for older devices - }; - - RID_Owner<CanvasLightShadow> canvas_light_shadow_owner; - - virtual RID canvas_light_shadow_buffer_create(int p_width); - - /* LIGHT SHADOW MAPPING */ - - struct CanvasOccluder : public RID_Data { - - GLuint array_id; // 0 means, unconfigured - GLuint vertex_id; // 0 means, unconfigured - GLuint index_id; // 0 means, unconfigured - PoolVector<Vector2> lines; - int len; - }; - - RID_Owner<CanvasOccluder> canvas_occluder_owner; - - virtual RID canvas_light_occluder_create(); - virtual void canvas_light_occluder_set_polylines(RID p_occluder, const PoolVector<Vector2> &p_lines); - - virtual VS::InstanceType get_base_type(RID p_rid) const; - - virtual bool free(RID p_rid); - - struct Frame { - - RenderTarget *current_rt; - - bool clear_request; - Color clear_request_color; - int canvas_draw_commands; - float time[4]; - float delta; - uint64_t count; - - } frame; - - void initialize(); - void finalize(); - - virtual bool has_os_feature(const String &p_feature) const; - - virtual void update_dirty_resources(); - - virtual void set_debug_generate_wireframes(bool p_generate); - - virtual void render_info_begin_capture(); - virtual void render_info_end_capture(); - virtual int get_captured_render_info(VS::RenderInfo p_info); - - virtual int get_render_info(VS::RenderInfo p_info); - virtual String get_video_adapter_name() const; - virtual String get_video_adapter_vendor() const; - - RasterizerStorageGLES3(); -}; - -#endif // RASTERIZERSTORAGEGLES3_H diff --git a/drivers/gles3/shader_compiler_gles3.cpp b/drivers/gles3/shader_compiler_gles3.cpp deleted file mode 100644 index 4e4d896bd7..0000000000 --- a/drivers/gles3/shader_compiler_gles3.cpp +++ /dev/null @@ -1,1072 +0,0 @@ -/*************************************************************************/ -/* shader_compiler_gles3.cpp */ -/*************************************************************************/ -/* 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. */ -/*************************************************************************/ - -#include "shader_compiler_gles3.h" - -#include "core/os/os.h" -#include "core/project_settings.h" - -#define SL ShaderLanguage - -static String _mktab(int p_level) { - - String tb; - for (int i = 0; i < p_level; i++) { - tb += "\t"; - } - - return tb; -} - -static String _typestr(SL::DataType p_type) { - - return ShaderLanguage::get_datatype_name(p_type); -} - -static int _get_datatype_size(SL::DataType p_type) { - - switch (p_type) { - - case SL::TYPE_VOID: return 0; - case SL::TYPE_BOOL: return 4; - case SL::TYPE_BVEC2: return 8; - case SL::TYPE_BVEC3: return 12; - case SL::TYPE_BVEC4: return 16; - case SL::TYPE_INT: return 4; - case SL::TYPE_IVEC2: return 8; - case SL::TYPE_IVEC3: return 12; - case SL::TYPE_IVEC4: return 16; - case SL::TYPE_UINT: return 4; - case SL::TYPE_UVEC2: return 8; - case SL::TYPE_UVEC3: return 12; - case SL::TYPE_UVEC4: return 16; - case SL::TYPE_FLOAT: return 4; - case SL::TYPE_VEC2: return 8; - case SL::TYPE_VEC3: return 12; - case SL::TYPE_VEC4: return 16; - case SL::TYPE_MAT2: - return 32; //4 * 4 + 4 * 4 - case SL::TYPE_MAT3: - return 48; // 4 * 4 + 4 * 4 + 4 * 4 - case SL::TYPE_MAT4: return 64; - case SL::TYPE_SAMPLER2D: return 16; - case SL::TYPE_ISAMPLER2D: return 16; - case SL::TYPE_USAMPLER2D: return 16; - case SL::TYPE_SAMPLER2DARRAY: return 16; - case SL::TYPE_ISAMPLER2DARRAY: return 16; - case SL::TYPE_USAMPLER2DARRAY: return 16; - case SL::TYPE_SAMPLER3D: return 16; - case SL::TYPE_ISAMPLER3D: return 16; - case SL::TYPE_USAMPLER3D: return 16; - case SL::TYPE_SAMPLERCUBE: return 16; - } - - ERR_FAIL_V(0); -} - -static int _get_datatype_alignment(SL::DataType p_type) { - - switch (p_type) { - - case SL::TYPE_VOID: return 0; - case SL::TYPE_BOOL: return 4; - case SL::TYPE_BVEC2: return 8; - case SL::TYPE_BVEC3: return 16; - case SL::TYPE_BVEC4: return 16; - case SL::TYPE_INT: return 4; - case SL::TYPE_IVEC2: return 8; - case SL::TYPE_IVEC3: return 16; - case SL::TYPE_IVEC4: return 16; - case SL::TYPE_UINT: return 4; - case SL::TYPE_UVEC2: return 8; - case SL::TYPE_UVEC3: return 16; - case SL::TYPE_UVEC4: return 16; - case SL::TYPE_FLOAT: return 4; - case SL::TYPE_VEC2: return 8; - case SL::TYPE_VEC3: return 16; - case SL::TYPE_VEC4: return 16; - case SL::TYPE_MAT2: return 16; - case SL::TYPE_MAT3: return 16; - case SL::TYPE_MAT4: return 16; - case SL::TYPE_SAMPLER2D: return 16; - case SL::TYPE_ISAMPLER2D: return 16; - case SL::TYPE_USAMPLER2D: return 16; - case SL::TYPE_SAMPLER2DARRAY: return 16; - case SL::TYPE_ISAMPLER2DARRAY: return 16; - case SL::TYPE_USAMPLER2DARRAY: return 16; - case SL::TYPE_SAMPLER3D: return 16; - case SL::TYPE_ISAMPLER3D: return 16; - case SL::TYPE_USAMPLER3D: return 16; - case SL::TYPE_SAMPLERCUBE: return 16; - } - - ERR_FAIL_V(0); -} -static String _interpstr(SL::DataInterpolation p_interp) { - - switch (p_interp) { - case SL::INTERPOLATION_FLAT: return "flat "; - case SL::INTERPOLATION_SMOOTH: return ""; - } - return ""; -} - -static String _prestr(SL::DataPrecision p_pres) { - - switch (p_pres) { - case SL::PRECISION_LOWP: return "lowp "; - case SL::PRECISION_MEDIUMP: return "mediump "; - case SL::PRECISION_HIGHP: return "highp "; - case SL::PRECISION_DEFAULT: return ""; - } - return ""; -} - -static String _qualstr(SL::ArgumentQualifier p_qual) { - - switch (p_qual) { - case SL::ARGUMENT_QUALIFIER_IN: return ""; - case SL::ARGUMENT_QUALIFIER_OUT: return "out "; - case SL::ARGUMENT_QUALIFIER_INOUT: return "inout "; - } - return ""; -} - -static String _opstr(SL::Operator p_op) { - - return SL::get_operator_text(p_op); -} - -static String _mkid(const String &p_id) { - - String id = "m_" + p_id.replace("__", "_dus_"); - return id.replace("__", "_dus_"); //doubleunderscore is reserved in glsl -} - -static String f2sp0(float p_float) { - - String num = rtoss(p_float); - if (num.find(".") == -1 && num.find("e") == -1) { - num += ".0"; - } - return num; -} - -static String get_constant_text(SL::DataType p_type, const Vector<SL::ConstantNode::Value> &p_values) { - - switch (p_type) { - case SL::TYPE_BOOL: return p_values[0].boolean ? "true" : "false"; - case SL::TYPE_BVEC2: - case SL::TYPE_BVEC3: - case SL::TYPE_BVEC4: { - - String text = "bvec" + itos(p_type - SL::TYPE_BOOL + 1) + "("; - for (int i = 0; i < p_values.size(); i++) { - if (i > 0) - text += ","; - - text += p_values[i].boolean ? "true" : "false"; - } - text += ")"; - return text; - } - - case SL::TYPE_INT: return itos(p_values[0].sint); - case SL::TYPE_IVEC2: - case SL::TYPE_IVEC3: - case SL::TYPE_IVEC4: { - - String text = "ivec" + itos(p_type - SL::TYPE_INT + 1) + "("; - for (int i = 0; i < p_values.size(); i++) { - if (i > 0) - text += ","; - - text += itos(p_values[i].sint); - } - text += ")"; - return text; - - } break; - case SL::TYPE_UINT: return itos(p_values[0].uint) + "u"; - case SL::TYPE_UVEC2: - case SL::TYPE_UVEC3: - case SL::TYPE_UVEC4: { - - String text = "uvec" + itos(p_type - SL::TYPE_UINT + 1) + "("; - for (int i = 0; i < p_values.size(); i++) { - if (i > 0) - text += ","; - - text += itos(p_values[i].uint) + "u"; - } - text += ")"; - return text; - } break; - case SL::TYPE_FLOAT: return f2sp0(p_values[0].real); - case SL::TYPE_VEC2: - case SL::TYPE_VEC3: - case SL::TYPE_VEC4: { - - String text = "vec" + itos(p_type - SL::TYPE_FLOAT + 1) + "("; - for (int i = 0; i < p_values.size(); i++) { - if (i > 0) - text += ","; - - text += f2sp0(p_values[i].real); - } - text += ")"; - return text; - - } break; - case SL::TYPE_MAT2: - case SL::TYPE_MAT3: - case SL::TYPE_MAT4: { - - String text = "mat" + itos(p_type - SL::TYPE_MAT2 + 2) + "("; - for (int i = 0; i < p_values.size(); i++) { - if (i > 0) - text += ","; - - text += f2sp0(p_values[i].real); - } - text += ")"; - return text; - - } break; - default: ERR_FAIL_V(String()); - } -} - -void ShaderCompilerGLES3::_dump_function_deps(SL::ShaderNode *p_node, const StringName &p_for_func, const Map<StringName, String> &p_func_code, String &r_to_add, Set<StringName> &added) { - - int fidx = -1; - - for (int i = 0; i < p_node->functions.size(); i++) { - if (p_node->functions[i].name == p_for_func) { - fidx = i; - break; - } - } - - ERR_FAIL_COND(fidx == -1); - - for (Set<StringName>::Element *E = p_node->functions[fidx].uses_function.front(); E; E = E->next()) { - - if (added.has(E->get())) { - continue; //was added already - } - - _dump_function_deps(p_node, E->get(), p_func_code, r_to_add, added); - - SL::FunctionNode *fnode = NULL; - - for (int i = 0; i < p_node->functions.size(); i++) { - if (p_node->functions[i].name == E->get()) { - fnode = p_node->functions[i].function; - break; - } - } - - ERR_FAIL_COND(!fnode); - - r_to_add += "\n"; - - String header; - header = _typestr(fnode->return_type) + " " + _mkid(fnode->name) + "("; - for (int i = 0; i < fnode->arguments.size(); i++) { - - if (i > 0) - header += ", "; - header += _qualstr(fnode->arguments[i].qualifier) + _prestr(fnode->arguments[i].precision) + _typestr(fnode->arguments[i].type) + " " + _mkid(fnode->arguments[i].name); - } - - header += ")\n"; - r_to_add += header; - r_to_add += p_func_code[E->get()]; - - added.insert(E->get()); - } -} - -String ShaderCompilerGLES3::_dump_node_code(SL::Node *p_node, int p_level, GeneratedCode &r_gen_code, IdentifierActions &p_actions, const DefaultIdentifierActions &p_default_actions, bool p_assigning) { - - String code; - - switch (p_node->type) { - - case SL::Node::TYPE_SHADER: { - - SL::ShaderNode *pnode = (SL::ShaderNode *)p_node; - - for (int i = 0; i < pnode->render_modes.size(); i++) { - - if (p_default_actions.render_mode_defines.has(pnode->render_modes[i]) && !used_rmode_defines.has(pnode->render_modes[i])) { - - r_gen_code.defines.push_back(p_default_actions.render_mode_defines[pnode->render_modes[i]].utf8()); - used_rmode_defines.insert(pnode->render_modes[i]); - } - - if (p_actions.render_mode_flags.has(pnode->render_modes[i])) { - *p_actions.render_mode_flags[pnode->render_modes[i]] = true; - } - - if (p_actions.render_mode_values.has(pnode->render_modes[i])) { - Pair<int *, int> &p = p_actions.render_mode_values[pnode->render_modes[i]]; - *p.first = p.second; - } - } - - int max_texture_uniforms = 0; - int max_uniforms = 0; - - for (Map<StringName, SL::ShaderNode::Uniform>::Element *E = pnode->uniforms.front(); E; E = E->next()) { - if (SL::is_sampler_type(E->get().type)) - max_texture_uniforms++; - else - max_uniforms++; - } - - r_gen_code.texture_uniforms.resize(max_texture_uniforms); - r_gen_code.texture_hints.resize(max_texture_uniforms); - r_gen_code.texture_types.resize(max_texture_uniforms); - - Vector<int> uniform_sizes; - Vector<int> uniform_alignments; - Vector<StringName> uniform_defines; - uniform_sizes.resize(max_uniforms); - uniform_alignments.resize(max_uniforms); - uniform_defines.resize(max_uniforms); - bool uses_uniforms = false; - - for (Map<StringName, SL::ShaderNode::Uniform>::Element *E = pnode->uniforms.front(); E; E = E->next()) { - - String ucode; - - if (SL::is_sampler_type(E->get().type)) { - ucode = "uniform "; - } - - ucode += _prestr(E->get().precision); - ucode += _typestr(E->get().type); - ucode += " " + _mkid(E->key()); - ucode += ";\n"; - if (SL::is_sampler_type(E->get().type)) { - r_gen_code.vertex_global += ucode; - r_gen_code.fragment_global += ucode; - r_gen_code.texture_uniforms.write[E->get().texture_order] = _mkid(E->key()); - r_gen_code.texture_hints.write[E->get().texture_order] = E->get().hint; - r_gen_code.texture_types.write[E->get().texture_order] = E->get().type; - } else { - if (!uses_uniforms) { - - r_gen_code.defines.push_back(String("#define USE_MATERIAL\n").ascii()); - uses_uniforms = true; - } - uniform_defines.write[E->get().order] = ucode; - uniform_sizes.write[E->get().order] = _get_datatype_size(E->get().type); - uniform_alignments.write[E->get().order] = _get_datatype_alignment(E->get().type); - } - - p_actions.uniforms->insert(E->key(), E->get()); - } - - for (int i = 0; i < max_uniforms; i++) { - r_gen_code.uniforms += uniform_defines[i]; - } - - // add up - int offset = 0; - for (int i = 0; i < uniform_sizes.size(); i++) { - - int align = offset % uniform_alignments[i]; - - if (align != 0) { - offset += uniform_alignments[i] - align; - } - - r_gen_code.uniform_offsets.push_back(offset); - - offset += uniform_sizes[i]; - } - - r_gen_code.uniform_total_size = offset; - if (r_gen_code.uniform_total_size % 16 != 0) { //UBO sizes must be multiples of 16 - r_gen_code.uniform_total_size += r_gen_code.uniform_total_size % 16; - } - - for (Map<StringName, SL::ShaderNode::Varying>::Element *E = pnode->varyings.front(); E; E = E->next()) { - - String vcode; - String interp_mode = _interpstr(E->get().interpolation); - vcode += _prestr(E->get().precision); - vcode += _typestr(E->get().type); - vcode += " " + _mkid(E->key()); - if (E->get().array_size > 0) { - vcode += "["; - vcode += itos(E->get().array_size); - vcode += "]"; - } - vcode += ";\n"; - r_gen_code.vertex_global += interp_mode + "out " + vcode; - r_gen_code.fragment_global += interp_mode + "in " + vcode; - } - - for (Map<StringName, SL::ShaderNode::Constant>::Element *E = pnode->constants.front(); E; E = E->next()) { - String gcode; - gcode += "const "; - gcode += _prestr(E->get().precision); - gcode += _typestr(E->get().type); - gcode += " " + _mkid(E->key()); - gcode += "="; - gcode += _dump_node_code(E->get().initializer, p_level, r_gen_code, p_actions, p_default_actions, p_assigning); - gcode += ";\n"; - r_gen_code.vertex_global += gcode; - r_gen_code.fragment_global += gcode; - } - - Map<StringName, String> function_code; - - //code for functions - for (int i = 0; i < pnode->functions.size(); i++) { - SL::FunctionNode *fnode = pnode->functions[i].function; - current_func_name = fnode->name; - function_code[fnode->name] = _dump_node_code(fnode->body, p_level + 1, r_gen_code, p_actions, p_default_actions, p_assigning); - } - - //place functions in actual code - - Set<StringName> added_vtx; - Set<StringName> added_fragment; //share for light - - for (int i = 0; i < pnode->functions.size(); i++) { - - SL::FunctionNode *fnode = pnode->functions[i].function; - - current_func_name = fnode->name; - - if (fnode->name == vertex_name) { - - _dump_function_deps(pnode, fnode->name, function_code, r_gen_code.vertex_global, added_vtx); - r_gen_code.vertex = function_code[vertex_name]; - } - - if (fnode->name == fragment_name) { - - _dump_function_deps(pnode, fnode->name, function_code, r_gen_code.fragment_global, added_fragment); - r_gen_code.fragment = function_code[fragment_name]; - } - - if (fnode->name == light_name) { - - _dump_function_deps(pnode, fnode->name, function_code, r_gen_code.fragment_global, added_fragment); - r_gen_code.light = function_code[light_name]; - } - } - - //code+=dump_node_code(pnode->body,p_level); - } break; - case SL::Node::TYPE_FUNCTION: { - - } break; - case SL::Node::TYPE_BLOCK: { - SL::BlockNode *bnode = (SL::BlockNode *)p_node; - - //variables - if (!bnode->single_statement) { - code += _mktab(p_level - 1) + "{\n"; - } - - for (int i = 0; i < bnode->statements.size(); i++) { - - String scode = _dump_node_code(bnode->statements[i], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); - - if (bnode->statements[i]->type == SL::Node::TYPE_CONTROL_FLOW || bnode->single_statement) { - code += scode; //use directly - } else { - code += _mktab(p_level) + scode + ";\n"; - } - } - if (!bnode->single_statement) { - code += _mktab(p_level - 1) + "}\n"; - } - - } break; - case SL::Node::TYPE_VARIABLE_DECLARATION: { - SL::VariableDeclarationNode *vdnode = (SL::VariableDeclarationNode *)p_node; - - String declaration; - if (vdnode->is_const) { - declaration += "const "; - } - declaration += _prestr(vdnode->precision); - declaration += _typestr(vdnode->datatype); - for (int i = 0; i < vdnode->declarations.size(); i++) { - if (i > 0) { - declaration += ","; - } else { - declaration += " "; - } - declaration += _mkid(vdnode->declarations[i].name); - if (vdnode->declarations[i].initializer) { - declaration += "="; - declaration += _dump_node_code(vdnode->declarations[i].initializer, p_level, r_gen_code, p_actions, p_default_actions, p_assigning); - } - } - - code += declaration; - } break; - case SL::Node::TYPE_VARIABLE: { - SL::VariableNode *vnode = (SL::VariableNode *)p_node; - - if (p_assigning && p_actions.write_flag_pointers.has(vnode->name)) { - *p_actions.write_flag_pointers[vnode->name] = true; - } - - if (p_default_actions.usage_defines.has(vnode->name) && !used_name_defines.has(vnode->name)) { - String define = p_default_actions.usage_defines[vnode->name]; - if (define.begins_with("@")) { - define = p_default_actions.usage_defines[define.substr(1, define.length())]; - } - r_gen_code.defines.push_back(define.utf8()); - used_name_defines.insert(vnode->name); - } - - if (p_actions.usage_flag_pointers.has(vnode->name) && !used_flag_pointers.has(vnode->name)) { - *p_actions.usage_flag_pointers[vnode->name] = true; - used_flag_pointers.insert(vnode->name); - } - - if (p_default_actions.renames.has(vnode->name)) - code = p_default_actions.renames[vnode->name]; - else - code = _mkid(vnode->name); - - if (vnode->name == time_name) { - if (current_func_name == vertex_name) { - r_gen_code.uses_vertex_time = true; - } - if (current_func_name == fragment_name || current_func_name == light_name) { - r_gen_code.uses_fragment_time = true; - } - } - - } break; - case SL::Node::TYPE_ARRAY_DECLARATION: { - - SL::ArrayDeclarationNode *adnode = (SL::ArrayDeclarationNode *)p_node; - - String declaration; - if (adnode->is_const) { - declaration += "const "; - } - declaration += _prestr(adnode->precision); - declaration += _typestr(adnode->datatype); - for (int i = 0; i < adnode->declarations.size(); i++) { - if (i > 0) { - declaration += ","; - } else { - declaration += " "; - } - declaration += _mkid(adnode->declarations[i].name); - declaration += "["; - declaration += itos(adnode->declarations[i].size); - declaration += "]"; - int sz = adnode->declarations[i].initializer.size(); - if (sz > 0) { - declaration += "="; - declaration += _typestr(adnode->datatype); - declaration += "["; - declaration += itos(sz); - declaration += "]"; - declaration += "("; - for (int j = 0; j < sz; j++) { - declaration += _dump_node_code(adnode->declarations[i].initializer[j], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); - if (j != sz - 1) { - declaration += ", "; - } - } - declaration += ")"; - } - } - - code += declaration; - } break; - case SL::Node::TYPE_ARRAY: { - SL::ArrayNode *anode = (SL::ArrayNode *)p_node; - - if (p_assigning && p_actions.write_flag_pointers.has(anode->name)) { - *p_actions.write_flag_pointers[anode->name] = true; - } - - if (p_default_actions.usage_defines.has(anode->name) && !used_name_defines.has(anode->name)) { - String define = p_default_actions.usage_defines[anode->name]; - if (define.begins_with("@")) { - define = p_default_actions.usage_defines[define.substr(1, define.length())]; - } - r_gen_code.defines.push_back(define.utf8()); - used_name_defines.insert(anode->name); - } - - if (p_actions.usage_flag_pointers.has(anode->name) && !used_flag_pointers.has(anode->name)) { - *p_actions.usage_flag_pointers[anode->name] = true; - used_flag_pointers.insert(anode->name); - } - - if (p_default_actions.renames.has(anode->name)) - code = p_default_actions.renames[anode->name]; - else - code = _mkid(anode->name); - - if (anode->call_expression != NULL) { - code += "."; - code += _dump_node_code(anode->call_expression, p_level, r_gen_code, p_actions, p_default_actions, p_assigning); - } - - if (anode->index_expression != NULL) { - code += "["; - code += _dump_node_code(anode->index_expression, p_level, r_gen_code, p_actions, p_default_actions, p_assigning); - code += "]"; - } - - if (anode->name == time_name) { - if (current_func_name == vertex_name) { - r_gen_code.uses_vertex_time = true; - } - if (current_func_name == fragment_name || current_func_name == light_name) { - r_gen_code.uses_fragment_time = true; - } - } - - } break; - case SL::Node::TYPE_CONSTANT: { - SL::ConstantNode *cnode = (SL::ConstantNode *)p_node; - return get_constant_text(cnode->datatype, cnode->values); - - } break; - case SL::Node::TYPE_OPERATOR: { - SL::OperatorNode *onode = (SL::OperatorNode *)p_node; - - switch (onode->op) { - - case SL::OP_ASSIGN: - case SL::OP_ASSIGN_ADD: - case SL::OP_ASSIGN_SUB: - case SL::OP_ASSIGN_MUL: - case SL::OP_ASSIGN_DIV: - case SL::OP_ASSIGN_SHIFT_LEFT: - case SL::OP_ASSIGN_SHIFT_RIGHT: - case SL::OP_ASSIGN_MOD: - case SL::OP_ASSIGN_BIT_AND: - case SL::OP_ASSIGN_BIT_OR: - case SL::OP_ASSIGN_BIT_XOR: - code = _dump_node_code(onode->arguments[0], p_level, r_gen_code, p_actions, p_default_actions, true) + _opstr(onode->op) + _dump_node_code(onode->arguments[1], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); - break; - case SL::OP_BIT_INVERT: - case SL::OP_NEGATE: - case SL::OP_NOT: - case SL::OP_DECREMENT: - case SL::OP_INCREMENT: - code = _opstr(onode->op) + _dump_node_code(onode->arguments[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); - break; - case SL::OP_POST_DECREMENT: - case SL::OP_POST_INCREMENT: - code = _dump_node_code(onode->arguments[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning) + _opstr(onode->op); - break; - case SL::OP_CALL: - case SL::OP_CONSTRUCT: { - - ERR_FAIL_COND_V(onode->arguments[0]->type != SL::Node::TYPE_VARIABLE, String()); - - SL::VariableNode *vnode = (SL::VariableNode *)onode->arguments[0]; - - if (onode->op == SL::OP_CONSTRUCT) { - code += String(vnode->name); - } else { - - if (internal_functions.has(vnode->name)) { - code += vnode->name; - } else if (p_default_actions.renames.has(vnode->name)) { - code += p_default_actions.renames[vnode->name]; - } else { - code += _mkid(vnode->name); - } - } - - code += "("; - - for (int i = 1; i < onode->arguments.size(); i++) { - if (i > 1) - code += ", "; - code += _dump_node_code(onode->arguments[i], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); - } - code += ")"; - } break; - case SL::OP_INDEX: { - - code += _dump_node_code(onode->arguments[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); - code += "["; - code += _dump_node_code(onode->arguments[1], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); - code += "]"; - - } break; - case SL::OP_SELECT_IF: { - - code += "("; - code += _dump_node_code(onode->arguments[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); - code += "?"; - code += _dump_node_code(onode->arguments[1], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); - code += ":"; - code += _dump_node_code(onode->arguments[2], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); - code += ")"; - - } break; - - default: { - - code = "(" + _dump_node_code(onode->arguments[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning) + _opstr(onode->op) + _dump_node_code(onode->arguments[1], p_level, r_gen_code, p_actions, p_default_actions, p_assigning) + ")"; - break; - } - } - - } break; - case SL::Node::TYPE_CONTROL_FLOW: { - SL::ControlFlowNode *cfnode = (SL::ControlFlowNode *)p_node; - if (cfnode->flow_op == SL::FLOW_OP_IF) { - - code += _mktab(p_level) + "if (" + _dump_node_code(cfnode->expressions[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning) + ")\n"; - code += _dump_node_code(cfnode->blocks[0], p_level + 1, r_gen_code, p_actions, p_default_actions, p_assigning); - if (cfnode->blocks.size() == 2) { - - code += _mktab(p_level) + "else\n"; - code += _dump_node_code(cfnode->blocks[1], p_level + 1, r_gen_code, p_actions, p_default_actions, p_assigning); - } - } else if (cfnode->flow_op == SL::FLOW_OP_SWITCH) { - code += _mktab(p_level) + "switch (" + _dump_node_code(cfnode->expressions[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning) + ")\n"; - code += _dump_node_code(cfnode->blocks[0], p_level + 1, r_gen_code, p_actions, p_default_actions, p_assigning); - } else if (cfnode->flow_op == SL::FLOW_OP_CASE) { - code += _mktab(p_level) + "case " + _dump_node_code(cfnode->expressions[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning) + ":\n"; - code += _dump_node_code(cfnode->blocks[0], p_level + 1, r_gen_code, p_actions, p_default_actions, p_assigning); - } else if (cfnode->flow_op == SL::FLOW_OP_DEFAULT) { - code += _mktab(p_level) + "default:\n"; - code += _dump_node_code(cfnode->blocks[0], p_level + 1, r_gen_code, p_actions, p_default_actions, p_assigning); - } else if (cfnode->flow_op == SL::FLOW_OP_DO) { - code += _mktab(p_level) + "do"; - code += _dump_node_code(cfnode->blocks[0], p_level + 1, r_gen_code, p_actions, p_default_actions, p_assigning); - code += _mktab(p_level) + "while (" + _dump_node_code(cfnode->expressions[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning) + ");"; - - } else if (cfnode->flow_op == SL::FLOW_OP_WHILE) { - - code += _mktab(p_level) + "while (" + _dump_node_code(cfnode->expressions[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning) + ")\n"; - code += _dump_node_code(cfnode->blocks[0], p_level + 1, r_gen_code, p_actions, p_default_actions, p_assigning); - } else if (cfnode->flow_op == SL::FLOW_OP_FOR) { - - String left = _dump_node_code(cfnode->blocks[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); - String middle = _dump_node_code(cfnode->expressions[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); - String right = _dump_node_code(cfnode->expressions[1], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); - code += _mktab(p_level) + "for (" + left + ";" + middle + ";" + right + ")\n"; - code += _dump_node_code(cfnode->blocks[1], p_level + 1, r_gen_code, p_actions, p_default_actions, p_assigning); - - } else if (cfnode->flow_op == SL::FLOW_OP_RETURN) { - - if (cfnode->expressions.size()) { - code = "return " + _dump_node_code(cfnode->expressions[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning) + ";"; - } else { - code = "return;"; - } - } else if (cfnode->flow_op == SL::FLOW_OP_DISCARD) { - - if (p_actions.usage_flag_pointers.has("DISCARD") && !used_flag_pointers.has("DISCARD")) { - *p_actions.usage_flag_pointers["DISCARD"] = true; - used_flag_pointers.insert("DISCARD"); - } - - code = "discard;"; - } else if (cfnode->flow_op == SL::FLOW_OP_CONTINUE) { - - code = "continue;"; - } else if (cfnode->flow_op == SL::FLOW_OP_BREAK) { - - code = "break;"; - } - - } break; - case SL::Node::TYPE_MEMBER: { - SL::MemberNode *mnode = (SL::MemberNode *)p_node; - code = _dump_node_code(mnode->owner, p_level, r_gen_code, p_actions, p_default_actions, p_assigning) + "." + mnode->name; - - } break; - } - - return code; -} - -Error ShaderCompilerGLES3::compile(VS::ShaderMode p_mode, const String &p_code, IdentifierActions *p_actions, const String &p_path, GeneratedCode &r_gen_code) { - - Error err = parser.compile(p_code, ShaderTypes::get_singleton()->get_functions(p_mode), ShaderTypes::get_singleton()->get_modes(p_mode), ShaderTypes::get_singleton()->get_types()); - - if (err != OK) { - - Vector<String> shader = p_code.split("\n"); - for (int i = 0; i < shader.size(); i++) { - print_line(itos(i + 1) + " " + shader[i]); - } - - _err_print_error(NULL, p_path.utf8().get_data(), parser.get_error_line(), parser.get_error_text().utf8().get_data(), ERR_HANDLER_SHADER); - return err; - } - - r_gen_code.defines.clear(); - r_gen_code.vertex = String(); - r_gen_code.vertex_global = String(); - r_gen_code.fragment = String(); - r_gen_code.fragment_global = String(); - r_gen_code.light = String(); - r_gen_code.uses_fragment_time = false; - r_gen_code.uses_vertex_time = false; - - used_name_defines.clear(); - used_rmode_defines.clear(); - used_flag_pointers.clear(); - - _dump_node_code(parser.get_shader(), 1, r_gen_code, *p_actions, actions[p_mode], false); - - if (r_gen_code.uniform_total_size) { //uniforms used? - int md = sizeof(float) * 4; - if (r_gen_code.uniform_total_size % md) { - r_gen_code.uniform_total_size += md - (r_gen_code.uniform_total_size % md); - } - r_gen_code.uniform_total_size += md; //pad just in case - } - - return OK; -} - -ShaderCompilerGLES3::ShaderCompilerGLES3() { - - /** CANVAS ITEM SHADER **/ - - actions[VS::SHADER_CANVAS_ITEM].renames["VERTEX"] = "outvec.xy"; - actions[VS::SHADER_CANVAS_ITEM].renames["UV"] = "uv"; - actions[VS::SHADER_CANVAS_ITEM].renames["POINT_SIZE"] = "point_size"; - - actions[VS::SHADER_CANVAS_ITEM].renames["WORLD_MATRIX"] = "modelview_matrix"; - actions[VS::SHADER_CANVAS_ITEM].renames["PROJECTION_MATRIX"] = "projection_matrix"; - actions[VS::SHADER_CANVAS_ITEM].renames["EXTRA_MATRIX"] = "extra_matrix"; - actions[VS::SHADER_CANVAS_ITEM].renames["TIME"] = "time"; - actions[VS::SHADER_CANVAS_ITEM].renames["AT_LIGHT_PASS"] = "at_light_pass"; - actions[VS::SHADER_CANVAS_ITEM].renames["INSTANCE_CUSTOM"] = "instance_custom"; - - actions[VS::SHADER_CANVAS_ITEM].renames["COLOR"] = "color"; - actions[VS::SHADER_CANVAS_ITEM].renames["NORMAL"] = "normal"; - actions[VS::SHADER_CANVAS_ITEM].renames["NORMALMAP"] = "normal_map"; - actions[VS::SHADER_CANVAS_ITEM].renames["NORMALMAP_DEPTH"] = "normal_depth"; - actions[VS::SHADER_CANVAS_ITEM].renames["TEXTURE"] = "color_texture"; - actions[VS::SHADER_CANVAS_ITEM].renames["TEXTURE_PIXEL_SIZE"] = "color_texpixel_size"; - actions[VS::SHADER_CANVAS_ITEM].renames["NORMAL_TEXTURE"] = "normal_texture"; - actions[VS::SHADER_CANVAS_ITEM].renames["SCREEN_UV"] = "screen_uv"; - actions[VS::SHADER_CANVAS_ITEM].renames["SCREEN_TEXTURE"] = "screen_texture"; - actions[VS::SHADER_CANVAS_ITEM].renames["SCREEN_PIXEL_SIZE"] = "screen_pixel_size"; - actions[VS::SHADER_CANVAS_ITEM].renames["FRAGCOORD"] = "gl_FragCoord"; - actions[VS::SHADER_CANVAS_ITEM].renames["POINT_COORD"] = "gl_PointCoord"; - - actions[VS::SHADER_CANVAS_ITEM].renames["LIGHT_VEC"] = "light_vec"; - actions[VS::SHADER_CANVAS_ITEM].renames["LIGHT_HEIGHT"] = "light_height"; - actions[VS::SHADER_CANVAS_ITEM].renames["LIGHT_COLOR"] = "light_color"; - actions[VS::SHADER_CANVAS_ITEM].renames["LIGHT_UV"] = "light_uv"; - actions[VS::SHADER_CANVAS_ITEM].renames["LIGHT"] = "light"; - actions[VS::SHADER_CANVAS_ITEM].renames["SHADOW_COLOR"] = "shadow_color"; - actions[VS::SHADER_CANVAS_ITEM].renames["SHADOW_VEC"] = "shadow_vec"; - - actions[VS::SHADER_CANVAS_ITEM].usage_defines["COLOR"] = "#define COLOR_USED\n"; - actions[VS::SHADER_CANVAS_ITEM].usage_defines["SCREEN_TEXTURE"] = "#define SCREEN_TEXTURE_USED\n"; - actions[VS::SHADER_CANVAS_ITEM].usage_defines["SCREEN_UV"] = "#define SCREEN_UV_USED\n"; - actions[VS::SHADER_CANVAS_ITEM].usage_defines["SCREEN_PIXEL_SIZE"] = "@SCREEN_UV"; - actions[VS::SHADER_CANVAS_ITEM].usage_defines["NORMAL"] = "#define NORMAL_USED\n"; - actions[VS::SHADER_CANVAS_ITEM].usage_defines["NORMALMAP"] = "#define NORMALMAP_USED\n"; - actions[VS::SHADER_CANVAS_ITEM].usage_defines["LIGHT"] = "#define USE_LIGHT_SHADER_CODE\n"; - actions[VS::SHADER_CANVAS_ITEM].usage_defines["SHADOW_VEC"] = "#define SHADOW_VEC_USED\n"; - actions[VS::SHADER_CANVAS_ITEM].render_mode_defines["skip_vertex_transform"] = "#define SKIP_TRANSFORM_USED\n"; - - /** SPATIAL SHADER **/ - - actions[VS::SHADER_SPATIAL].renames["WORLD_MATRIX"] = "world_transform"; - actions[VS::SHADER_SPATIAL].renames["INV_CAMERA_MATRIX"] = "camera_inverse_matrix"; - actions[VS::SHADER_SPATIAL].renames["CAMERA_MATRIX"] = "camera_matrix"; - actions[VS::SHADER_SPATIAL].renames["PROJECTION_MATRIX"] = "projection_matrix"; - actions[VS::SHADER_SPATIAL].renames["INV_PROJECTION_MATRIX"] = "inv_projection_matrix"; - actions[VS::SHADER_SPATIAL].renames["MODELVIEW_MATRIX"] = "modelview"; - - actions[VS::SHADER_SPATIAL].renames["VERTEX"] = "vertex.xyz"; - actions[VS::SHADER_SPATIAL].renames["NORMAL"] = "normal"; - actions[VS::SHADER_SPATIAL].renames["TANGENT"] = "tangent"; - actions[VS::SHADER_SPATIAL].renames["BINORMAL"] = "binormal"; - actions[VS::SHADER_SPATIAL].renames["POSITION"] = "position"; - actions[VS::SHADER_SPATIAL].renames["UV"] = "uv_interp"; - actions[VS::SHADER_SPATIAL].renames["UV2"] = "uv2_interp"; - actions[VS::SHADER_SPATIAL].renames["COLOR"] = "color_interp"; - actions[VS::SHADER_SPATIAL].renames["POINT_SIZE"] = "point_size"; - actions[VS::SHADER_SPATIAL].renames["INSTANCE_ID"] = "gl_InstanceID"; - - //builtins - - actions[VS::SHADER_SPATIAL].renames["TIME"] = "time"; - actions[VS::SHADER_SPATIAL].renames["VIEWPORT_SIZE"] = "viewport_size"; - - actions[VS::SHADER_SPATIAL].renames["FRAGCOORD"] = "gl_FragCoord"; - actions[VS::SHADER_SPATIAL].renames["FRONT_FACING"] = "gl_FrontFacing"; - actions[VS::SHADER_SPATIAL].renames["NORMALMAP"] = "normalmap"; - actions[VS::SHADER_SPATIAL].renames["NORMALMAP_DEPTH"] = "normaldepth"; - actions[VS::SHADER_SPATIAL].renames["ALBEDO"] = "albedo"; - actions[VS::SHADER_SPATIAL].renames["ALPHA"] = "alpha"; - actions[VS::SHADER_SPATIAL].renames["METALLIC"] = "metallic"; - actions[VS::SHADER_SPATIAL].renames["SPECULAR"] = "specular"; - actions[VS::SHADER_SPATIAL].renames["ROUGHNESS"] = "roughness"; - actions[VS::SHADER_SPATIAL].renames["RIM"] = "rim"; - actions[VS::SHADER_SPATIAL].renames["RIM_TINT"] = "rim_tint"; - actions[VS::SHADER_SPATIAL].renames["CLEARCOAT"] = "clearcoat"; - actions[VS::SHADER_SPATIAL].renames["CLEARCOAT_GLOSS"] = "clearcoat_gloss"; - actions[VS::SHADER_SPATIAL].renames["ANISOTROPY"] = "anisotropy"; - actions[VS::SHADER_SPATIAL].renames["ANISOTROPY_FLOW"] = "anisotropy_flow"; - actions[VS::SHADER_SPATIAL].renames["SSS_STRENGTH"] = "sss_strength"; - actions[VS::SHADER_SPATIAL].renames["TRANSMISSION"] = "transmission"; - actions[VS::SHADER_SPATIAL].renames["AO"] = "ao"; - actions[VS::SHADER_SPATIAL].renames["AO_LIGHT_AFFECT"] = "ao_light_affect"; - actions[VS::SHADER_SPATIAL].renames["EMISSION"] = "emission"; - actions[VS::SHADER_SPATIAL].renames["POINT_COORD"] = "gl_PointCoord"; - actions[VS::SHADER_SPATIAL].renames["INSTANCE_CUSTOM"] = "instance_custom"; - actions[VS::SHADER_SPATIAL].renames["SCREEN_UV"] = "screen_uv"; - actions[VS::SHADER_SPATIAL].renames["SCREEN_TEXTURE"] = "screen_texture"; - actions[VS::SHADER_SPATIAL].renames["DEPTH_TEXTURE"] = "depth_buffer"; - actions[VS::SHADER_SPATIAL].renames["DEPTH"] = "gl_FragDepth"; - actions[VS::SHADER_SPATIAL].renames["ALPHA_SCISSOR"] = "alpha_scissor"; - actions[VS::SHADER_SPATIAL].renames["OUTPUT_IS_SRGB"] = "SHADER_IS_SRGB"; - - //for light - actions[VS::SHADER_SPATIAL].renames["VIEW"] = "view"; - actions[VS::SHADER_SPATIAL].renames["LIGHT_COLOR"] = "light_color"; - actions[VS::SHADER_SPATIAL].renames["LIGHT"] = "light"; - actions[VS::SHADER_SPATIAL].renames["ATTENUATION"] = "attenuation"; - actions[VS::SHADER_SPATIAL].renames["DIFFUSE_LIGHT"] = "diffuse_light"; - actions[VS::SHADER_SPATIAL].renames["SPECULAR_LIGHT"] = "specular_light"; - - actions[VS::SHADER_SPATIAL].usage_defines["TANGENT"] = "#define ENABLE_TANGENT_INTERP\n"; - actions[VS::SHADER_SPATIAL].usage_defines["BINORMAL"] = "@TANGENT"; - actions[VS::SHADER_SPATIAL].usage_defines["RIM"] = "#define LIGHT_USE_RIM\n"; - actions[VS::SHADER_SPATIAL].usage_defines["RIM_TINT"] = "@RIM"; - actions[VS::SHADER_SPATIAL].usage_defines["CLEARCOAT"] = "#define LIGHT_USE_CLEARCOAT\n"; - actions[VS::SHADER_SPATIAL].usage_defines["CLEARCOAT_GLOSS"] = "@CLEARCOAT"; - actions[VS::SHADER_SPATIAL].usage_defines["ANISOTROPY"] = "#define LIGHT_USE_ANISOTROPY\n"; - actions[VS::SHADER_SPATIAL].usage_defines["ANISOTROPY_FLOW"] = "@ANISOTROPY"; - actions[VS::SHADER_SPATIAL].usage_defines["AO"] = "#define ENABLE_AO\n"; - actions[VS::SHADER_SPATIAL].usage_defines["AO_LIGHT_AFFECT"] = "#define ENABLE_AO\n"; - actions[VS::SHADER_SPATIAL].usage_defines["UV"] = "#define ENABLE_UV_INTERP\n"; - actions[VS::SHADER_SPATIAL].usage_defines["UV2"] = "#define ENABLE_UV2_INTERP\n"; - actions[VS::SHADER_SPATIAL].usage_defines["NORMALMAP"] = "#define ENABLE_NORMALMAP\n"; - actions[VS::SHADER_SPATIAL].usage_defines["NORMALMAP_DEPTH"] = "@NORMALMAP"; - actions[VS::SHADER_SPATIAL].usage_defines["COLOR"] = "#define ENABLE_COLOR_INTERP\n"; - actions[VS::SHADER_SPATIAL].usage_defines["INSTANCE_CUSTOM"] = "#define ENABLE_INSTANCE_CUSTOM\n"; - actions[VS::SHADER_SPATIAL].usage_defines["ALPHA_SCISSOR"] = "#define ALPHA_SCISSOR_USED\n"; - actions[VS::SHADER_SPATIAL].usage_defines["POSITION"] = "#define OVERRIDE_POSITION\n"; - - actions[VS::SHADER_SPATIAL].usage_defines["SSS_STRENGTH"] = "#define ENABLE_SSS\n"; - actions[VS::SHADER_SPATIAL].usage_defines["TRANSMISSION"] = "#define TRANSMISSION_USED\n"; - actions[VS::SHADER_SPATIAL].usage_defines["SCREEN_TEXTURE"] = "#define SCREEN_TEXTURE_USED\n"; - actions[VS::SHADER_SPATIAL].usage_defines["SCREEN_UV"] = "#define SCREEN_UV_USED\n"; - - actions[VS::SHADER_SPATIAL].usage_defines["DIFFUSE_LIGHT"] = "#define USE_LIGHT_SHADER_CODE\n"; - actions[VS::SHADER_SPATIAL].usage_defines["SPECULAR_LIGHT"] = "#define USE_LIGHT_SHADER_CODE\n"; - - actions[VS::SHADER_SPATIAL].render_mode_defines["skip_vertex_transform"] = "#define SKIP_TRANSFORM_USED\n"; - actions[VS::SHADER_SPATIAL].render_mode_defines["world_vertex_coords"] = "#define VERTEX_WORLD_COORDS_USED\n"; - actions[VS::SHADER_SPATIAL].render_mode_defines["ensure_correct_normals"] = "#define ENSURE_CORRECT_NORMALS\n"; - actions[VS::SHADER_SPATIAL].render_mode_defines["cull_front"] = "#define DO_SIDE_CHECK\n"; - actions[VS::SHADER_SPATIAL].render_mode_defines["cull_disabled"] = "#define DO_SIDE_CHECK\n"; - - bool force_lambert = GLOBAL_GET("rendering/quality/shading/force_lambert_over_burley"); - - if (!force_lambert) { - actions[VS::SHADER_SPATIAL].render_mode_defines["diffuse_burley"] = "#define DIFFUSE_BURLEY\n"; - } - - actions[VS::SHADER_SPATIAL].render_mode_defines["diffuse_oren_nayar"] = "#define DIFFUSE_OREN_NAYAR\n"; - actions[VS::SHADER_SPATIAL].render_mode_defines["diffuse_lambert_wrap"] = "#define DIFFUSE_LAMBERT_WRAP\n"; - actions[VS::SHADER_SPATIAL].render_mode_defines["diffuse_toon"] = "#define DIFFUSE_TOON\n"; - - bool force_blinn = GLOBAL_GET("rendering/quality/shading/force_blinn_over_ggx"); - - if (!force_blinn) { - actions[VS::SHADER_SPATIAL].render_mode_defines["specular_schlick_ggx"] = "#define SPECULAR_SCHLICK_GGX\n"; - } else { - actions[VS::SHADER_SPATIAL].render_mode_defines["specular_schlick_ggx"] = "#define SPECULAR_BLINN\n"; - } - - actions[VS::SHADER_SPATIAL].render_mode_defines["specular_blinn"] = "#define SPECULAR_BLINN\n"; - actions[VS::SHADER_SPATIAL].render_mode_defines["specular_phong"] = "#define SPECULAR_PHONG\n"; - actions[VS::SHADER_SPATIAL].render_mode_defines["specular_toon"] = "#define SPECULAR_TOON\n"; - actions[VS::SHADER_SPATIAL].render_mode_defines["specular_disabled"] = "#define SPECULAR_DISABLED\n"; - actions[VS::SHADER_SPATIAL].render_mode_defines["shadows_disabled"] = "#define SHADOWS_DISABLED\n"; - actions[VS::SHADER_SPATIAL].render_mode_defines["ambient_light_disabled"] = "#define AMBIENT_LIGHT_DISABLED\n"; - actions[VS::SHADER_SPATIAL].render_mode_defines["shadow_to_opacity"] = "#define USE_SHADOW_TO_OPACITY\n"; - - /* PARTICLES SHADER */ - - actions[VS::SHADER_PARTICLES].renames["COLOR"] = "out_color"; - actions[VS::SHADER_PARTICLES].renames["VELOCITY"] = "out_velocity_active.xyz"; - actions[VS::SHADER_PARTICLES].renames["MASS"] = "mass"; - actions[VS::SHADER_PARTICLES].renames["ACTIVE"] = "shader_active"; - actions[VS::SHADER_PARTICLES].renames["RESTART"] = "restart"; - actions[VS::SHADER_PARTICLES].renames["CUSTOM"] = "out_custom"; - actions[VS::SHADER_PARTICLES].renames["TRANSFORM"] = "xform"; - actions[VS::SHADER_PARTICLES].renames["TIME"] = "time"; - actions[VS::SHADER_PARTICLES].renames["LIFETIME"] = "lifetime"; - actions[VS::SHADER_PARTICLES].renames["DELTA"] = "local_delta"; - actions[VS::SHADER_PARTICLES].renames["NUMBER"] = "particle_number"; - actions[VS::SHADER_PARTICLES].renames["INDEX"] = "index"; - actions[VS::SHADER_PARTICLES].renames["GRAVITY"] = "current_gravity"; - actions[VS::SHADER_PARTICLES].renames["EMISSION_TRANSFORM"] = "emission_transform"; - actions[VS::SHADER_PARTICLES].renames["RANDOM_SEED"] = "random_seed"; - - actions[VS::SHADER_PARTICLES].render_mode_defines["disable_force"] = "#define DISABLE_FORCE\n"; - actions[VS::SHADER_PARTICLES].render_mode_defines["disable_velocity"] = "#define DISABLE_VELOCITY\n"; - actions[VS::SHADER_PARTICLES].render_mode_defines["keep_data"] = "#define ENABLE_KEEP_DATA\n"; - - vertex_name = "vertex"; - fragment_name = "fragment"; - light_name = "light"; - time_name = "TIME"; - - List<String> func_list; - - ShaderLanguage::get_builtin_funcs(&func_list); - - for (List<String>::Element *E = func_list.front(); E; E = E->next()) { - internal_functions.insert(E->get()); - } -} diff --git a/drivers/gles3/shader_compiler_gles3.h b/drivers/gles3/shader_compiler_gles3.h deleted file mode 100644 index 08e08241d1..0000000000 --- a/drivers/gles3/shader_compiler_gles3.h +++ /dev/null @@ -1,103 +0,0 @@ -/*************************************************************************/ -/* shader_compiler_gles3.h */ -/*************************************************************************/ -/* 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. */ -/*************************************************************************/ - -#ifndef SHADERCOMPILERGLES3_H -#define SHADERCOMPILERGLES3_H - -#include "core/pair.h" -#include "servers/visual/shader_language.h" -#include "servers/visual/shader_types.h" -#include "servers/visual_server.h" - -class ShaderCompilerGLES3 { -public: - struct IdentifierActions { - - Map<StringName, Pair<int *, int> > render_mode_values; - Map<StringName, bool *> render_mode_flags; - Map<StringName, bool *> usage_flag_pointers; - Map<StringName, bool *> write_flag_pointers; - - Map<StringName, ShaderLanguage::ShaderNode::Uniform> *uniforms; - }; - - struct GeneratedCode { - - Vector<CharString> defines; - Vector<StringName> texture_uniforms; - Vector<ShaderLanguage::DataType> texture_types; - Vector<ShaderLanguage::ShaderNode::Uniform::Hint> texture_hints; - - Vector<uint32_t> uniform_offsets; - uint32_t uniform_total_size; - String uniforms; - String vertex_global; - String vertex; - String fragment_global; - String fragment; - String light; - - bool uses_fragment_time; - bool uses_vertex_time; - }; - -private: - ShaderLanguage parser; - - struct DefaultIdentifierActions { - - Map<StringName, String> renames; - Map<StringName, String> render_mode_defines; - Map<StringName, String> usage_defines; - }; - - void _dump_function_deps(ShaderLanguage::ShaderNode *p_node, const StringName &p_for_func, const Map<StringName, String> &p_func_code, String &r_to_add, Set<StringName> &added); - String _dump_node_code(ShaderLanguage::Node *p_node, int p_level, GeneratedCode &r_gen_code, IdentifierActions &p_actions, const DefaultIdentifierActions &p_default_actions, bool p_assigning); - - StringName current_func_name; - StringName vertex_name; - StringName fragment_name; - StringName light_name; - StringName time_name; - - Set<StringName> used_name_defines; - Set<StringName> used_flag_pointers; - Set<StringName> used_rmode_defines; - Set<StringName> internal_functions; - - DefaultIdentifierActions actions[VS::SHADER_MAX]; - -public: - Error compile(VS::ShaderMode p_mode, const String &p_code, IdentifierActions *p_actions, const String &p_path, GeneratedCode &r_gen_code); - - ShaderCompilerGLES3(); -}; - -#endif // SHADERCOMPILERGLES3_H diff --git a/drivers/gles3/shader_gles3.cpp b/drivers/gles3/shader_gles3.cpp deleted file mode 100644 index 5d269e22f0..0000000000 --- a/drivers/gles3/shader_gles3.cpp +++ /dev/null @@ -1,777 +0,0 @@ -/*************************************************************************/ -/* shader_gles3.cpp */ -/*************************************************************************/ -/* 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. */ -/*************************************************************************/ - -#include "shader_gles3.h" - -#include "core/print_string.h" - -//#define DEBUG_OPENGL - -#ifdef DEBUG_OPENGL - -#define DEBUG_TEST_ERROR(m_section) \ - { \ - uint32_t err = glGetError(); \ - if (err) { \ - print_line("OpenGL Error #" + itos(err) + " at: " + m_section); \ - } \ - } -#else - -#define DEBUG_TEST_ERROR(m_section) - -#endif - -ShaderGLES3 *ShaderGLES3::active = NULL; - -//#define DEBUG_SHADER - -#ifdef DEBUG_SHADER - -#define DEBUG_PRINT(m_text) print_line(m_text); - -#else - -#define DEBUG_PRINT(m_text) - -#endif - -void ShaderGLES3::bind_uniforms() { - - if (!uniforms_dirty) { - return; - }; - - // upload default uniforms - const Map<uint32_t, Variant>::Element *E = uniform_defaults.front(); - - while (E) { - int idx = E->key(); - int location = version->uniform_location[idx]; - - if (location < 0) { - E = E->next(); - continue; - } - - const Variant &v = E->value(); - _set_uniform_variant(location, v); - //print_line("uniform "+itos(location)+" value "+v+ " type "+Variant::get_type_name(v.get_type())); - E = E->next(); - }; - - const Map<uint32_t, CameraMatrix>::Element *C = uniform_cameras.front(); - while (C) { - - int location = version->uniform_location[C->key()]; - if (location < 0) { - C = C->next(); - continue; - } - - glUniformMatrix4fv(location, 1, false, &(C->get().matrix[0][0])); - C = C->next(); - }; - - uniforms_dirty = false; -} - -GLint ShaderGLES3::get_uniform_location(int p_index) const { - - ERR_FAIL_COND_V(!version, -1); - - return version->uniform_location[p_index]; -} - -bool ShaderGLES3::bind() { - - if (active != this || !version || new_conditional_version.key != conditional_version.key) { - conditional_version = new_conditional_version; - version = get_current_version(); - } else { - - return false; - } - - ERR_FAIL_COND_V(!version, false); - - if (!version->ok) { //broken, unable to bind (do not throw error, you saw it before already when it failed compilation). - glUseProgram(0); - return false; - } - - glUseProgram(version->id); - - DEBUG_TEST_ERROR("Use Program"); - - active = this; - uniforms_dirty = true; - return true; -} - -void ShaderGLES3::unbind() { - - version = NULL; - glUseProgram(0); - uniforms_dirty = true; - active = NULL; -} - -static void _display_error_with_code(const String &p_error, const Vector<const char *> &p_code) { - - int line = 1; - String total_code; - - for (int i = 0; i < p_code.size(); i++) { - total_code += String(p_code[i]); - } - - Vector<String> lines = String(total_code).split("\n"); - - for (int j = 0; j < lines.size(); j++) { - - print_line(itos(line) + ": " + lines[j]); - line++; - } - - ERR_PRINTS(p_error); -} - -ShaderGLES3::Version *ShaderGLES3::get_current_version() { - - Version *_v = version_map.getptr(conditional_version); - - if (_v) { - - if (conditional_version.code_version != 0) { - CustomCode *cc = custom_code_map.getptr(conditional_version.code_version); - ERR_FAIL_COND_V(!cc, _v); - if (cc->version == _v->code_version) - return _v; - } else { - return _v; - } - } - - if (!_v) - version_map[conditional_version] = Version(); - - Version &v = version_map[conditional_version]; - - if (!_v) { - - v.uniform_location = memnew_arr(GLint, uniform_count); - - } else { - if (v.ok) { - //bye bye shaders - glDeleteShader(v.vert_id); - glDeleteShader(v.frag_id); - glDeleteProgram(v.id); - v.id = 0; - } - } - - v.ok = false; - /* SETUP CONDITIONALS */ - - Vector<const char *> strings; -#ifdef GLES_OVER_GL - strings.push_back("#version 330\n"); - strings.push_back("#define GLES_OVER_GL\n"); -#else - strings.push_back("#version 300 es\n"); -#endif - - for (int i = 0; i < custom_defines.size(); i++) { - - strings.push_back(custom_defines[i].get_data()); - } - - for (int j = 0; j < conditional_count; j++) { - - bool enable = ((1 << j) & conditional_version.version); - strings.push_back(enable ? conditional_defines[j] : ""); - - if (enable) { - DEBUG_PRINT(conditional_defines[j]); - } - } - - //keep them around during the function - CharString code_string; - CharString code_string2; - CharString code_globals; - CharString material_string; - - CustomCode *cc = NULL; - - if (conditional_version.code_version > 0) { - //do custom code related stuff - - ERR_FAIL_COND_V(!custom_code_map.has(conditional_version.code_version), NULL); - cc = &custom_code_map[conditional_version.code_version]; - v.code_version = cc->version; - } - - /* CREATE PROGRAM */ - - v.id = glCreateProgram(); - - ERR_FAIL_COND_V(v.id == 0, NULL); - - /* VERTEX SHADER */ - - if (cc) { - for (int i = 0; i < cc->custom_defines.size(); i++) { - - strings.push_back(cc->custom_defines[i].get_data()); - DEBUG_PRINT("CD #" + itos(i) + ": " + String(cc->custom_defines[i])); - } - } - - int strings_base_size = strings.size(); - - //vertex precision is high - strings.push_back("precision highp float;\n"); - strings.push_back("precision highp int;\n"); -#ifndef GLES_OVER_GL - strings.push_back("precision highp sampler2D;\n"); - strings.push_back("precision highp samplerCube;\n"); - strings.push_back("precision highp sampler2DArray;\n"); -#endif - - strings.push_back(vertex_code0.get_data()); - - if (cc) { - material_string = cc->uniforms.ascii(); - strings.push_back(material_string.get_data()); - } - - strings.push_back(vertex_code1.get_data()); - - if (cc) { - code_globals = cc->vertex_globals.ascii(); - strings.push_back(code_globals.get_data()); - } - - strings.push_back(vertex_code2.get_data()); - - if (cc) { - code_string = cc->vertex.ascii(); - strings.push_back(code_string.get_data()); - } - - strings.push_back(vertex_code3.get_data()); -#ifdef DEBUG_SHADER - - DEBUG_PRINT("\nVertex Code:\n\n" + String(code_string.get_data())); - for (int i = 0; i < strings.size(); i++) { - - //print_line("vert strings "+itos(i)+":"+String(strings[i])); - } -#endif - - v.vert_id = glCreateShader(GL_VERTEX_SHADER); - glShaderSource(v.vert_id, strings.size(), &strings[0], NULL); - glCompileShader(v.vert_id); - - GLint status; - - glGetShaderiv(v.vert_id, GL_COMPILE_STATUS, &status); - if (status == GL_FALSE) { - // error compiling - GLsizei iloglen; - glGetShaderiv(v.vert_id, GL_INFO_LOG_LENGTH, &iloglen); - - if (iloglen < 0) { - - glDeleteShader(v.vert_id); - glDeleteProgram(v.id); - v.id = 0; - - ERR_PRINT("Vertex shader compilation failed with empty log"); - } else { - - if (iloglen == 0) { - - iloglen = 4096; //buggy driver (Adreno 220+....) - } - - char *ilogmem = (char *)memalloc(iloglen + 1); - ilogmem[iloglen] = 0; - glGetShaderInfoLog(v.vert_id, iloglen, &iloglen, ilogmem); - - String err_string = get_shader_name() + ": Vertex Program Compilation Failed:\n"; - - err_string += ilogmem; - _display_error_with_code(err_string, strings); - memfree(ilogmem); - glDeleteShader(v.vert_id); - glDeleteProgram(v.id); - v.id = 0; - } - - ERR_FAIL_V(NULL); - } - - //_display_error_with_code("pepo", strings); - - /* FRAGMENT SHADER */ - - strings.resize(strings_base_size); - //fragment precision is medium - strings.push_back("precision highp float;\n"); - strings.push_back("precision highp int;\n"); -#ifndef GLES_OVER_GL - strings.push_back("precision highp sampler2D;\n"); - strings.push_back("precision highp samplerCube;\n"); - strings.push_back("precision highp sampler2DArray;\n"); -#endif - - strings.push_back(fragment_code0.get_data()); - if (cc) { - material_string = cc->uniforms.ascii(); - strings.push_back(material_string.get_data()); - } - - strings.push_back(fragment_code1.get_data()); - - if (cc) { - code_globals = cc->fragment_globals.ascii(); - strings.push_back(code_globals.get_data()); - } - - strings.push_back(fragment_code2.get_data()); - - if (cc) { - code_string = cc->light.ascii(); - strings.push_back(code_string.get_data()); - } - - strings.push_back(fragment_code3.get_data()); - - if (cc) { - code_string2 = cc->fragment.ascii(); - strings.push_back(code_string2.get_data()); - } - - strings.push_back(fragment_code4.get_data()); - -#ifdef DEBUG_SHADER - DEBUG_PRINT("\nFragment Globals:\n\n" + String(code_globals.get_data())); - DEBUG_PRINT("\nFragment Code:\n\n" + String(code_string2.get_data())); - for (int i = 0; i < strings.size(); i++) { - - //print_line("frag strings "+itos(i)+":"+String(strings[i])); - } -#endif - - v.frag_id = glCreateShader(GL_FRAGMENT_SHADER); - glShaderSource(v.frag_id, strings.size(), &strings[0], NULL); - glCompileShader(v.frag_id); - - glGetShaderiv(v.frag_id, GL_COMPILE_STATUS, &status); - if (status == GL_FALSE) { - // error compiling - GLsizei iloglen; - glGetShaderiv(v.frag_id, GL_INFO_LOG_LENGTH, &iloglen); - - if (iloglen < 0) { - - glDeleteShader(v.frag_id); - glDeleteShader(v.vert_id); - glDeleteProgram(v.id); - v.id = 0; - ERR_PRINT("Fragment shader compilation failed with empty log"); - } else { - - if (iloglen == 0) { - - iloglen = 4096; //buggy driver (Adreno 220+....) - } - - char *ilogmem = (char *)memalloc(iloglen + 1); - ilogmem[iloglen] = 0; - glGetShaderInfoLog(v.frag_id, iloglen, &iloglen, ilogmem); - - String err_string = get_shader_name() + ": Fragment Program Compilation Failed:\n"; - - err_string += ilogmem; - _display_error_with_code(err_string, strings); - ERR_PRINT(err_string.ascii().get_data()); - memfree(ilogmem); - glDeleteShader(v.frag_id); - glDeleteShader(v.vert_id); - glDeleteProgram(v.id); - v.id = 0; - } - - ERR_FAIL_V(NULL); - } - - glAttachShader(v.id, v.frag_id); - glAttachShader(v.id, v.vert_id); - - // bind attributes before linking - for (int i = 0; i < attribute_pair_count; i++) { - - glBindAttribLocation(v.id, attribute_pairs[i].index, attribute_pairs[i].name); - } - - //if feedback exists, set it up - - if (feedback_count) { - Vector<const char *> feedback; - for (int i = 0; i < feedback_count; i++) { - - if (feedbacks[i].conditional == -1 || (1 << feedbacks[i].conditional) & conditional_version.version) { - //conditional for this feedback is enabled - feedback.push_back(feedbacks[i].name); - } - } - - if (feedback.size()) { - glTransformFeedbackVaryings(v.id, feedback.size(), feedback.ptr(), GL_INTERLEAVED_ATTRIBS); - } - } - - glLinkProgram(v.id); - - glGetProgramiv(v.id, GL_LINK_STATUS, &status); - - if (status == GL_FALSE) { - // error linking - GLsizei iloglen; - glGetProgramiv(v.id, GL_INFO_LOG_LENGTH, &iloglen); - - if (iloglen < 0) { - - glDeleteShader(v.frag_id); - glDeleteShader(v.vert_id); - glDeleteProgram(v.id); - v.id = 0; - ERR_FAIL_COND_V(iloglen < 0, NULL); - } - - if (iloglen == 0) { - - iloglen = 4096; //buggy driver (Adreno 220+....) - } - - char *ilogmem = (char *)Memory::alloc_static(iloglen + 1); - ilogmem[iloglen] = 0; - glGetProgramInfoLog(v.id, iloglen, &iloglen, ilogmem); - - String err_string = get_shader_name() + ": Program LINK FAILED:\n"; - - err_string += ilogmem; - _display_error_with_code(err_string, strings); - ERR_PRINT(err_string.ascii().get_data()); - Memory::free_static(ilogmem); - glDeleteShader(v.frag_id); - glDeleteShader(v.vert_id); - glDeleteProgram(v.id); - v.id = 0; - - ERR_FAIL_V(NULL); - } - - /* UNIFORMS */ - - glUseProgram(v.id); - - //print_line("uniforms: "); - for (int j = 0; j < uniform_count; j++) { - - v.uniform_location[j] = glGetUniformLocation(v.id, uniform_names[j]); - //print_line("uniform "+String(uniform_names[j])+" location "+itos(v.uniform_location[j])); - } - - // set texture uniforms - for (int i = 0; i < texunit_pair_count; i++) { - - GLint loc = glGetUniformLocation(v.id, texunit_pairs[i].name); - if (loc >= 0) { - if (texunit_pairs[i].index < 0) { - glUniform1i(loc, max_image_units + texunit_pairs[i].index); //negative, goes down - } else { - - glUniform1i(loc, texunit_pairs[i].index); - } - } - } - - // assign uniform block bind points - for (int i = 0; i < ubo_count; i++) { - - GLint loc = glGetUniformBlockIndex(v.id, ubo_pairs[i].name); - if (loc >= 0) - glUniformBlockBinding(v.id, loc, ubo_pairs[i].index); - } - - if (cc) { - - v.texture_uniform_locations.resize(cc->texture_uniforms.size()); - for (int i = 0; i < cc->texture_uniforms.size(); i++) { - - v.texture_uniform_locations.write[i] = glGetUniformLocation(v.id, String(cc->texture_uniforms[i]).ascii().get_data()); - glUniform1i(v.texture_uniform_locations[i], i + base_material_tex_index); - } - } - - glUseProgram(0); - - v.ok = true; - if (cc) { - cc->versions.insert(conditional_version.version); - } - - return &v; -} - -GLint ShaderGLES3::get_uniform_location(const String &p_name) const { - - ERR_FAIL_COND_V(!version, -1); - return glGetUniformLocation(version->id, p_name.ascii().get_data()); -} - -void ShaderGLES3::setup(const char **p_conditional_defines, int p_conditional_count, const char **p_uniform_names, int p_uniform_count, const AttributePair *p_attribute_pairs, int p_attribute_count, const TexUnitPair *p_texunit_pairs, int p_texunit_pair_count, const UBOPair *p_ubo_pairs, int p_ubo_pair_count, const Feedback *p_feedback, int p_feedback_count, const char *p_vertex_code, const char *p_fragment_code, int p_vertex_code_start, int p_fragment_code_start) { - - ERR_FAIL_COND(version); - conditional_version.key = 0; - new_conditional_version.key = 0; - uniform_count = p_uniform_count; - conditional_count = p_conditional_count; - conditional_defines = p_conditional_defines; - uniform_names = p_uniform_names; - vertex_code = p_vertex_code; - fragment_code = p_fragment_code; - texunit_pairs = p_texunit_pairs; - texunit_pair_count = p_texunit_pair_count; - vertex_code_start = p_vertex_code_start; - fragment_code_start = p_fragment_code_start; - attribute_pairs = p_attribute_pairs; - attribute_pair_count = p_attribute_count; - ubo_pairs = p_ubo_pairs; - ubo_count = p_ubo_pair_count; - feedbacks = p_feedback; - feedback_count = p_feedback_count; - - //split vertex and shader code (thank you, shader compiler programmers from you know what company). - { - String globals_tag = "\nVERTEX_SHADER_GLOBALS"; - String material_tag = "\nMATERIAL_UNIFORMS"; - String code_tag = "\nVERTEX_SHADER_CODE"; - String code = vertex_code; - int cpos = code.find(material_tag); - if (cpos == -1) { - vertex_code0 = code.ascii(); - } else { - vertex_code0 = code.substr(0, cpos).ascii(); - code = code.substr(cpos + material_tag.length(), code.length()); - - cpos = code.find(globals_tag); - - if (cpos == -1) { - vertex_code1 = code.ascii(); - } else { - - vertex_code1 = code.substr(0, cpos).ascii(); - String code2 = code.substr(cpos + globals_tag.length(), code.length()); - - cpos = code2.find(code_tag); - if (cpos == -1) { - vertex_code2 = code2.ascii(); - } else { - - vertex_code2 = code2.substr(0, cpos).ascii(); - vertex_code3 = code2.substr(cpos + code_tag.length(), code2.length()).ascii(); - } - } - } - } - - { - String globals_tag = "\nFRAGMENT_SHADER_GLOBALS"; - String material_tag = "\nMATERIAL_UNIFORMS"; - String code_tag = "\nFRAGMENT_SHADER_CODE"; - String light_code_tag = "\nLIGHT_SHADER_CODE"; - String code = fragment_code; - int cpos = code.find(material_tag); - if (cpos == -1) { - fragment_code0 = code.ascii(); - } else { - fragment_code0 = code.substr(0, cpos).ascii(); - //print_line("CODE0:\n"+String(fragment_code0.get_data())); - code = code.substr(cpos + material_tag.length(), code.length()); - cpos = code.find(globals_tag); - - if (cpos == -1) { - fragment_code1 = code.ascii(); - } else { - - fragment_code1 = code.substr(0, cpos).ascii(); - //print_line("CODE1:\n"+String(fragment_code1.get_data())); - - String code2 = code.substr(cpos + globals_tag.length(), code.length()); - cpos = code2.find(light_code_tag); - - if (cpos == -1) { - fragment_code2 = code2.ascii(); - } else { - - fragment_code2 = code2.substr(0, cpos).ascii(); - //print_line("CODE2:\n"+String(fragment_code2.get_data())); - - String code3 = code2.substr(cpos + light_code_tag.length(), code2.length()); - - cpos = code3.find(code_tag); - if (cpos == -1) { - fragment_code3 = code3.ascii(); - } else { - - fragment_code3 = code3.substr(0, cpos).ascii(); - //print_line("CODE3:\n"+String(fragment_code3.get_data())); - fragment_code4 = code3.substr(cpos + code_tag.length(), code3.length()).ascii(); - //print_line("CODE4:\n"+String(fragment_code4.get_data())); - } - } - } - } - } - - glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &max_image_units); -} - -void ShaderGLES3::finish() { - - const VersionKey *V = NULL; - while ((V = version_map.next(V))) { - - Version &v = version_map[*V]; - glDeleteShader(v.vert_id); - glDeleteShader(v.frag_id); - glDeleteProgram(v.id); - memdelete_arr(v.uniform_location); - } -} - -void ShaderGLES3::clear_caches() { - - const VersionKey *V = NULL; - while ((V = version_map.next(V))) { - - Version &v = version_map[*V]; - glDeleteShader(v.vert_id); - glDeleteShader(v.frag_id); - glDeleteProgram(v.id); - memdelete_arr(v.uniform_location); - } - - version_map.clear(); - - custom_code_map.clear(); - version = NULL; - last_custom_code = 1; - uniforms_dirty = true; -} - -uint32_t ShaderGLES3::create_custom_shader() { - - custom_code_map[last_custom_code] = CustomCode(); - custom_code_map[last_custom_code].version = 1; - return last_custom_code++; -} - -void ShaderGLES3::set_custom_shader_code(uint32_t p_code_id, const String &p_vertex, const String &p_vertex_globals, const String &p_fragment, const String &p_light, const String &p_fragment_globals, const String &p_uniforms, const Vector<StringName> &p_texture_uniforms, const Vector<CharString> &p_custom_defines) { - - ERR_FAIL_COND(!custom_code_map.has(p_code_id)); - CustomCode *cc = &custom_code_map[p_code_id]; - - cc->vertex = p_vertex; - cc->vertex_globals = p_vertex_globals; - cc->fragment = p_fragment; - cc->fragment_globals = p_fragment_globals; - cc->light = p_light; - cc->texture_uniforms = p_texture_uniforms; - cc->uniforms = p_uniforms; - cc->custom_defines = p_custom_defines; - cc->version++; -} - -void ShaderGLES3::set_custom_shader(uint32_t p_code_id) { - - new_conditional_version.code_version = p_code_id; -} - -void ShaderGLES3::free_custom_shader(uint32_t p_code_id) { - - ERR_FAIL_COND(!custom_code_map.has(p_code_id)); - if (conditional_version.code_version == p_code_id) { - conditional_version.code_version = 0; //do not keep using a version that is going away - unbind(); - } - - VersionKey key; - key.code_version = p_code_id; - for (Set<uint32_t>::Element *E = custom_code_map[p_code_id].versions.front(); E; E = E->next()) { - key.version = E->get(); - ERR_CONTINUE(!version_map.has(key)); - Version &v = version_map[key]; - - glDeleteShader(v.vert_id); - glDeleteShader(v.frag_id); - glDeleteProgram(v.id); - memdelete_arr(v.uniform_location); - v.id = 0; - - version_map.erase(key); - } - - custom_code_map.erase(p_code_id); -} - -void ShaderGLES3::set_base_material_tex_index(int p_idx) { - - base_material_tex_index = p_idx; -} - -ShaderGLES3::ShaderGLES3() { - version = NULL; - last_custom_code = 1; - uniforms_dirty = true; - base_material_tex_index = 0; -} - -ShaderGLES3::~ShaderGLES3() { - - finish(); -} diff --git a/drivers/gles3/shader_gles3.h b/drivers/gles3/shader_gles3.h deleted file mode 100644 index 2bfe72fbc0..0000000000 --- a/drivers/gles3/shader_gles3.h +++ /dev/null @@ -1,392 +0,0 @@ -/*************************************************************************/ -/* shader_gles3.h */ -/*************************************************************************/ -/* 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. */ -/*************************************************************************/ - -#ifndef SHADER_GLES3_H -#define SHADER_GLES3_H - -#include "core/hash_map.h" -#include "core/map.h" -#include "core/math/camera_matrix.h" -#include "core/variant.h" - -#include "platform_config.h" -#ifndef GLES3_INCLUDE_H -#include <GLES3/gl3.h> -#else -#include GLES3_INCLUDE_H -#endif - -#include <stdio.h> - -class ShaderGLES3 { -protected: - struct Enum { - - uint64_t mask; - uint64_t shift; - const char *defines[16]; - }; - - struct EnumValue { - - uint64_t set_mask; - uint64_t clear_mask; - }; - - struct AttributePair { - - const char *name; - int index; - }; - - struct UniformPair { - const char *name; - Variant::Type type_hint; - }; - - struct TexUnitPair { - - const char *name; - int index; - }; - - struct UBOPair { - - const char *name; - int index; - }; - - struct Feedback { - - const char *name; - int conditional; - }; - - bool uniforms_dirty; - -private: - //@TODO Optimize to a fixed set of shader pools and use a LRU - int uniform_count; - int texunit_pair_count; - int conditional_count; - int ubo_count; - int feedback_count; - int vertex_code_start; - int fragment_code_start; - int attribute_pair_count; - - struct CustomCode { - - String vertex; - String vertex_globals; - String fragment; - String fragment_globals; - String light; - String uniforms; - uint32_t version; - Vector<StringName> texture_uniforms; - Vector<CharString> custom_defines; - Set<uint32_t> versions; - }; - - struct Version { - - GLuint id; - GLuint vert_id; - GLuint frag_id; - GLint *uniform_location; - Vector<GLint> texture_uniform_locations; - uint32_t code_version; - bool ok; - Version() : - id(0), - vert_id(0), - frag_id(0), - uniform_location(NULL), - code_version(0), - ok(false) {} - }; - - Version *version; - - union VersionKey { - - struct { - uint32_t version; - uint32_t code_version; - }; - uint64_t key; - bool operator==(const VersionKey &p_key) const { return key == p_key.key; } - bool operator<(const VersionKey &p_key) const { return key < p_key.key; } - }; - - struct VersionKeyHash { - - static _FORCE_INLINE_ uint32_t hash(const VersionKey &p_key) { return HashMapHasherDefault::hash(p_key.key); }; - }; - - //this should use a way more cachefriendly version.. - HashMap<VersionKey, Version, VersionKeyHash> version_map; - - HashMap<uint32_t, CustomCode> custom_code_map; - uint32_t last_custom_code; - - VersionKey conditional_version; - VersionKey new_conditional_version; - - virtual String get_shader_name() const = 0; - - const char **conditional_defines; - const char **uniform_names; - const AttributePair *attribute_pairs; - const TexUnitPair *texunit_pairs; - const UBOPair *ubo_pairs; - const Feedback *feedbacks; - const char *vertex_code; - const char *fragment_code; - CharString fragment_code0; - CharString fragment_code1; - CharString fragment_code2; - CharString fragment_code3; - CharString fragment_code4; - - CharString vertex_code0; - CharString vertex_code1; - CharString vertex_code2; - CharString vertex_code3; - - Vector<CharString> custom_defines; - - int base_material_tex_index; - - Version *get_current_version(); - - static ShaderGLES3 *active; - - int max_image_units; - - _FORCE_INLINE_ void _set_uniform_variant(GLint p_uniform, const Variant &p_value) { - - if (p_uniform < 0) - return; // do none - switch (p_value.get_type()) { - - case Variant::BOOL: - case Variant::INT: { - - int val = p_value; - glUniform1i(p_uniform, val); - } break; - case Variant::REAL: { - - real_t val = p_value; - glUniform1f(p_uniform, val); - } break; - case Variant::COLOR: { - - Color val = p_value; - glUniform4f(p_uniform, val.r, val.g, val.b, val.a); - } break; - case Variant::VECTOR2: { - - Vector2 val = p_value; - glUniform2f(p_uniform, val.x, val.y); - } break; - case Variant::VECTOR3: { - - Vector3 val = p_value; - glUniform3f(p_uniform, val.x, val.y, val.z); - } break; - case Variant::PLANE: { - - Plane val = p_value; - glUniform4f(p_uniform, val.normal.x, val.normal.y, val.normal.z, val.d); - } break; - case Variant::QUAT: { - - Quat val = p_value; - glUniform4f(p_uniform, val.x, val.y, val.z, val.w); - } break; - - case Variant::TRANSFORM2D: { - - Transform2D tr = p_value; - GLfloat matrix[16] = { /* build a 16x16 matrix */ - tr.elements[0][0], - tr.elements[0][1], - 0, - 0, - tr.elements[1][0], - tr.elements[1][1], - 0, - 0, - 0, - 0, - 1, - 0, - tr.elements[2][0], - tr.elements[2][1], - 0, - 1 - }; - - glUniformMatrix4fv(p_uniform, 1, false, matrix); - - } break; - case Variant::BASIS: - case Variant::TRANSFORM: { - - Transform tr = p_value; - GLfloat matrix[16] = { /* build a 16x16 matrix */ - tr.basis.elements[0][0], - tr.basis.elements[1][0], - tr.basis.elements[2][0], - 0, - tr.basis.elements[0][1], - tr.basis.elements[1][1], - tr.basis.elements[2][1], - 0, - tr.basis.elements[0][2], - tr.basis.elements[1][2], - tr.basis.elements[2][2], - 0, - tr.origin.x, - tr.origin.y, - tr.origin.z, - 1 - }; - - glUniformMatrix4fv(p_uniform, 1, false, matrix); - } break; - default: { - ERR_FAIL(); - } // do nothing - } - } - - Map<uint32_t, Variant> uniform_defaults; - Map<uint32_t, CameraMatrix> uniform_cameras; - -protected: - _FORCE_INLINE_ int _get_uniform(int p_which) const; - _FORCE_INLINE_ void _set_conditional(int p_which, bool p_value); - - void setup(const char **p_conditional_defines, int p_conditional_count, const char **p_uniform_names, int p_uniform_count, const AttributePair *p_attribute_pairs, int p_attribute_count, const TexUnitPair *p_texunit_pairs, int p_texunit_pair_count, const UBOPair *p_ubo_pairs, int p_ubo_pair_count, const Feedback *p_feedback, int p_feedback_count, const char *p_vertex_code, const char *p_fragment_code, int p_vertex_code_start, int p_fragment_code_start); - - ShaderGLES3(); - -public: - enum { - CUSTOM_SHADER_DISABLED = 0 - }; - - GLint get_uniform_location(const String &p_name) const; - GLint get_uniform_location(int p_index) const; - - static _FORCE_INLINE_ ShaderGLES3 *get_active() { return active; }; - bool bind(); - void unbind(); - void bind_uniforms(); - - inline GLuint get_program() const { return version ? version->id : 0; } - - void clear_caches(); - - uint32_t create_custom_shader(); - void set_custom_shader_code(uint32_t p_code_id, const String &p_vertex, const String &p_vertex_globals, const String &p_fragment, const String &p_light, const String &p_fragment_globals, const String &p_uniforms, const Vector<StringName> &p_texture_uniforms, const Vector<CharString> &p_custom_defines); - void set_custom_shader(uint32_t p_code_id); - void free_custom_shader(uint32_t p_code_id); - - void set_uniform_default(int p_idx, const Variant &p_value) { - - if (p_value.get_type() == Variant::NIL) { - - uniform_defaults.erase(p_idx); - } else { - - uniform_defaults[p_idx] = p_value; - } - uniforms_dirty = true; - } - - uint32_t get_version() const { return new_conditional_version.version; } - _FORCE_INLINE_ bool is_version_valid() const { return version && version->ok; } - - void set_uniform_camera(int p_idx, const CameraMatrix &p_mat) { - - uniform_cameras[p_idx] = p_mat; - uniforms_dirty = true; - }; - - _FORCE_INLINE_ void set_texture_uniform(int p_idx, const Variant &p_value) { - - ERR_FAIL_COND(!version); - ERR_FAIL_INDEX(p_idx, version->texture_uniform_locations.size()); - _set_uniform_variant(version->texture_uniform_locations[p_idx], p_value); - } - - _FORCE_INLINE_ GLint get_texture_uniform_location(int p_idx) { - - ERR_FAIL_COND_V(!version, -1); - ERR_FAIL_INDEX_V(p_idx, version->texture_uniform_locations.size(), -1); - return version->texture_uniform_locations[p_idx]; - } - - virtual void init() = 0; - void finish(); - - void set_base_material_tex_index(int p_idx); - - void add_custom_define(const String &p_define) { - custom_defines.push_back(p_define.utf8()); - } - - virtual ~ShaderGLES3(); -}; - -// called a lot, made inline - -int ShaderGLES3::_get_uniform(int p_which) const { - - ERR_FAIL_INDEX_V(p_which, uniform_count, -1); - ERR_FAIL_COND_V(!version, -1); - return version->uniform_location[p_which]; -} - -void ShaderGLES3::_set_conditional(int p_which, bool p_value) { - - ERR_FAIL_INDEX(p_which, conditional_count); - if (p_value) - new_conditional_version.version |= (1 << p_which); - else - new_conditional_version.version &= ~(1 << p_which); -} - -#endif diff --git a/drivers/gles3/shaders/SCsub b/drivers/gles3/shaders/SCsub deleted file mode 100644 index 27fd1514e7..0000000000 --- a/drivers/gles3/shaders/SCsub +++ /dev/null @@ -1,23 +0,0 @@ -#!/usr/bin/env python - -Import('env') - -if 'GLES3_GLSL' in env['BUILDERS']: - env.GLES3_GLSL('copy.glsl'); - env.GLES3_GLSL('resolve.glsl'); - env.GLES3_GLSL('canvas.glsl'); - env.GLES3_GLSL('canvas_shadow.glsl'); - env.GLES3_GLSL('scene.glsl'); - env.GLES3_GLSL('cubemap_filter.glsl'); - env.GLES3_GLSL('cube_to_dp.glsl'); - env.GLES3_GLSL('blend_shape.glsl'); - env.GLES3_GLSL('screen_space_reflection.glsl'); - env.GLES3_GLSL('effect_blur.glsl'); - env.GLES3_GLSL('subsurf_scattering.glsl'); - env.GLES3_GLSL('ssao.glsl'); - env.GLES3_GLSL('ssao_minify.glsl'); - env.GLES3_GLSL('ssao_blur.glsl'); - env.GLES3_GLSL('exposure.glsl'); - env.GLES3_GLSL('tonemap.glsl'); - env.GLES3_GLSL('particles.glsl'); - env.GLES3_GLSL('lens_distorted.glsl'); diff --git a/drivers/gles3/shaders/blend_shape.glsl b/drivers/gles3/shaders/blend_shape.glsl deleted file mode 100644 index a1e954e33d..0000000000 --- a/drivers/gles3/shaders/blend_shape.glsl +++ /dev/null @@ -1,194 +0,0 @@ -/* clang-format off */ -[vertex] - -/* -from VisualServer: - -ARRAY_VERTEX=0, -ARRAY_NORMAL=1, -ARRAY_TANGENT=2, -ARRAY_COLOR=3, -ARRAY_TEX_UV=4, -ARRAY_TEX_UV2=5, -ARRAY_BONES=6, -ARRAY_WEIGHTS=7, -ARRAY_INDEX=8, -*/ - -#ifdef USE_2D_VERTEX -#define VFORMAT vec2 -#else -#define VFORMAT vec3 -#endif - -/* INPUT ATTRIBS */ - -layout(location = 0) in highp VFORMAT vertex_attrib; -/* clang-format on */ -layout(location = 1) in vec3 normal_attrib; - -#ifdef ENABLE_TANGENT -layout(location = 2) in vec4 tangent_attrib; -#endif - -#ifdef ENABLE_COLOR -layout(location = 3) in vec4 color_attrib; -#endif - -#ifdef ENABLE_UV -layout(location = 4) in vec2 uv_attrib; -#endif - -#ifdef ENABLE_UV2 -layout(location = 5) in vec2 uv2_attrib; -#endif - -#ifdef ENABLE_SKELETON -layout(location = 6) in ivec4 bone_attrib; -layout(location = 7) in vec4 weight_attrib; -#endif - -/* BLEND ATTRIBS */ - -#ifdef ENABLE_BLEND - -layout(location = 8) in highp VFORMAT vertex_attrib_blend; -layout(location = 9) in vec3 normal_attrib_blend; - -#ifdef ENABLE_TANGENT -layout(location = 10) in vec4 tangent_attrib_blend; -#endif - -#ifdef ENABLE_COLOR -layout(location = 11) in vec4 color_attrib_blend; -#endif - -#ifdef ENABLE_UV -layout(location = 12) in vec2 uv_attrib_blend; -#endif - -#ifdef ENABLE_UV2 -layout(location = 13) in vec2 uv2_attrib_blend; -#endif - -#ifdef ENABLE_SKELETON -layout(location = 14) in ivec4 bone_attrib_blend; -layout(location = 15) in vec4 weight_attrib_blend; -#endif - -#endif - -/* OUTPUTS */ - -out VFORMAT vertex_out; //tfb: - -#ifdef ENABLE_NORMAL -out vec3 normal_out; //tfb:ENABLE_NORMAL -#endif - -#ifdef ENABLE_TANGENT -out vec4 tangent_out; //tfb:ENABLE_TANGENT -#endif - -#ifdef ENABLE_COLOR -out vec4 color_out; //tfb:ENABLE_COLOR -#endif - -#ifdef ENABLE_UV -out vec2 uv_out; //tfb:ENABLE_UV -#endif - -#ifdef ENABLE_UV2 -out vec2 uv2_out; //tfb:ENABLE_UV2 -#endif - -#ifdef ENABLE_SKELETON -out ivec4 bone_out; //tfb:ENABLE_SKELETON -out vec4 weight_out; //tfb:ENABLE_SKELETON -#endif - -uniform float blend_amount; - -void main() { - -#ifdef ENABLE_BLEND - - vertex_out = vertex_attrib_blend + vertex_attrib * blend_amount; - -#ifdef ENABLE_NORMAL - normal_out = normal_attrib_blend + normal_attrib * blend_amount; -#endif - -#ifdef ENABLE_TANGENT - - tangent_out.xyz = tangent_attrib_blend.xyz + tangent_attrib.xyz * blend_amount; - tangent_out.w = tangent_attrib_blend.w; //just copy, no point in blending his -#endif - -#ifdef ENABLE_COLOR - - color_out = color_attrib_blend + color_attrib * blend_amount; -#endif - -#ifdef ENABLE_UV - - uv_out = uv_attrib_blend + uv_attrib * blend_amount; -#endif - -#ifdef ENABLE_UV2 - - uv2_out = uv2_attrib_blend + uv2_attrib * blend_amount; -#endif - -#ifdef ENABLE_SKELETON - - bone_out = bone_attrib_blend; - weight_out = weight_attrib_blend + weight_attrib * blend_amount; -#endif - -#else //ENABLE_BLEND - - vertex_out = vertex_attrib * blend_amount; - -#ifdef ENABLE_NORMAL - normal_out = normal_attrib * blend_amount; -#endif - -#ifdef ENABLE_TANGENT - - tangent_out.xyz = tangent_attrib.xyz * blend_amount; - tangent_out.w = tangent_attrib.w; //just copy, no point in blending his -#endif - -#ifdef ENABLE_COLOR - - color_out = color_attrib * blend_amount; -#endif - -#ifdef ENABLE_UV - - uv_out = uv_attrib * blend_amount; -#endif - -#ifdef ENABLE_UV2 - - uv2_out = uv2_attrib * blend_amount; -#endif - -#ifdef ENABLE_SKELETON - - bone_out = bone_attrib; - weight_out = weight_attrib * blend_amount; -#endif - -#endif - gl_Position = vec4(0.0); -} - -/* clang-format off */ -[fragment] - -void main() { - -} -/* clang-format on */ diff --git a/drivers/gles3/shaders/canvas.glsl b/drivers/gles3/shaders/canvas.glsl deleted file mode 100644 index 07ee9cd010..0000000000 --- a/drivers/gles3/shaders/canvas.glsl +++ /dev/null @@ -1,726 +0,0 @@ -/* clang-format off */ -[vertex] - -layout(location = 0) in highp vec2 vertex; -/* clang-format on */ -layout(location = 3) in vec4 color_attrib; - -#ifdef USE_SKELETON -layout(location = 6) in uvec4 bone_indices; // attrib:6 -layout(location = 7) in vec4 bone_weights; // attrib:7 -#endif - -#ifdef USE_TEXTURE_RECT - -uniform vec4 dst_rect; -uniform vec4 src_rect; - -#else - -#ifdef USE_INSTANCING - -layout(location = 8) in highp vec4 instance_xform0; -layout(location = 9) in highp vec4 instance_xform1; -layout(location = 10) in highp vec4 instance_xform2; -layout(location = 11) in lowp vec4 instance_color; - -#ifdef USE_INSTANCE_CUSTOM -layout(location = 12) in highp vec4 instance_custom_data; -#endif - -#endif - -layout(location = 4) in highp vec2 uv_attrib; - -// skeleton -#endif - -uniform highp vec2 color_texpixel_size; - -layout(std140) uniform CanvasItemData { //ubo:0 - - highp mat4 projection_matrix; - highp float time; -}; - -uniform highp mat4 modelview_matrix; -uniform highp mat4 extra_matrix; - -out highp vec2 uv_interp; -out mediump vec4 color_interp; - -#ifdef USE_NINEPATCH - -out highp vec2 pixel_size_interp; -#endif - -#ifdef USE_SKELETON -uniform mediump sampler2D skeleton_texture; // texunit:-4 -uniform highp mat4 skeleton_transform; -uniform highp mat4 skeleton_transform_inverse; -#endif - -#ifdef USE_LIGHTING - -layout(std140) uniform LightData { //ubo:1 - - // light matrices - highp mat4 light_matrix; - highp mat4 light_local_matrix; - highp mat4 shadow_matrix; - highp vec4 light_color; - highp vec4 light_shadow_color; - highp vec2 light_pos; - highp float shadowpixel_size; - highp float shadow_gradient; - highp float light_height; - highp float light_outside_alpha; - highp float shadow_distance_mult; -}; - -out vec4 light_uv_interp; -out vec2 transformed_light_uv; - -out vec4 local_rot; - -#ifdef USE_SHADOWS -out highp vec2 pos; -#endif - -const bool at_light_pass = true; -#else -const bool at_light_pass = false; -#endif - -#if defined(USE_MATERIAL) - -/* clang-format off */ -layout(std140) uniform UniformData { //ubo:2 - -MATERIAL_UNIFORMS - -}; -/* clang-format on */ - -#endif - -/* clang-format off */ - -VERTEX_SHADER_GLOBALS - -/* clang-format on */ - -void main() { - - vec4 color = color_attrib; - -#ifdef USE_INSTANCING - mat4 extra_matrix_instance = extra_matrix * transpose(mat4(instance_xform0, instance_xform1, instance_xform2, vec4(0.0, 0.0, 0.0, 1.0))); - color *= instance_color; - -#ifdef USE_INSTANCE_CUSTOM - vec4 instance_custom = instance_custom_data; -#else - vec4 instance_custom = vec4(0.0); -#endif - -#else - mat4 extra_matrix_instance = extra_matrix; - vec4 instance_custom = vec4(0.0); -#endif - -#ifdef USE_TEXTURE_RECT - - if (dst_rect.z < 0.0) { // Transpose is encoded as negative dst_rect.z - uv_interp = src_rect.xy + abs(src_rect.zw) * vertex.yx; - } else { - uv_interp = src_rect.xy + abs(src_rect.zw) * vertex; - } - highp vec4 outvec = vec4(dst_rect.xy + abs(dst_rect.zw) * mix(vertex, vec2(1.0, 1.0) - vertex, lessThan(src_rect.zw, vec2(0.0, 0.0))), 0.0, 1.0); - -#else - uv_interp = uv_attrib; - highp vec4 outvec = vec4(vertex, 0.0, 1.0); -#endif - -#ifdef USE_PARTICLES - //scale by texture size - outvec.xy /= color_texpixel_size; -#endif - -#define extra_matrix extra_matrix_instance - - float point_size = 1.0; - //for compatibility with the fragment shader we need to use uv here - vec2 uv = uv_interp; - { - /* clang-format off */ - -VERTEX_SHADER_CODE - - /* clang-format on */ - } - - gl_PointSize = point_size; - uv_interp = uv; - -#ifdef USE_NINEPATCH - - pixel_size_interp = abs(dst_rect.zw) * vertex; -#endif - -#if !defined(SKIP_TRANSFORM_USED) - outvec = extra_matrix * outvec; - outvec = modelview_matrix * outvec; -#endif - -#undef extra_matrix - - color_interp = color; - -#ifdef USE_PIXEL_SNAP - outvec.xy = floor(outvec + 0.5).xy; - // precision issue on some hardware creates artifacts within texture - // offset uv by a small amount to avoid - uv_interp += 1e-5; -#endif - -#ifdef USE_SKELETON - - if (bone_weights != vec4(0.0)) { //must be a valid bone - //skeleton transform - - ivec4 bone_indicesi = ivec4(bone_indices); - - ivec2 tex_ofs = ivec2(bone_indicesi.x % 256, (bone_indicesi.x / 256) * 2); - - highp mat2x4 m; - m = mat2x4( - texelFetch(skeleton_texture, tex_ofs, 0), - texelFetch(skeleton_texture, tex_ofs + ivec2(0, 1), 0)) * - bone_weights.x; - - tex_ofs = ivec2(bone_indicesi.y % 256, (bone_indicesi.y / 256) * 2); - - m += mat2x4( - texelFetch(skeleton_texture, tex_ofs, 0), - texelFetch(skeleton_texture, tex_ofs + ivec2(0, 1), 0)) * - bone_weights.y; - - tex_ofs = ivec2(bone_indicesi.z % 256, (bone_indicesi.z / 256) * 2); - - m += mat2x4( - texelFetch(skeleton_texture, tex_ofs, 0), - texelFetch(skeleton_texture, tex_ofs + ivec2(0, 1), 0)) * - bone_weights.z; - - tex_ofs = ivec2(bone_indicesi.w % 256, (bone_indicesi.w / 256) * 2); - - m += mat2x4( - texelFetch(skeleton_texture, tex_ofs, 0), - texelFetch(skeleton_texture, tex_ofs + ivec2(0, 1), 0)) * - bone_weights.w; - - mat4 bone_matrix = skeleton_transform * transpose(mat4(m[0], m[1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0))) * skeleton_transform_inverse; - - outvec = bone_matrix * outvec; - } - -#endif - - gl_Position = projection_matrix * outvec; - -#ifdef USE_LIGHTING - - light_uv_interp.xy = (light_matrix * outvec).xy; - light_uv_interp.zw = (light_local_matrix * outvec).xy; - - mat3 inverse_light_matrix = mat3(inverse(light_matrix)); - inverse_light_matrix[0] = normalize(inverse_light_matrix[0]); - inverse_light_matrix[1] = normalize(inverse_light_matrix[1]); - inverse_light_matrix[2] = normalize(inverse_light_matrix[2]); - transformed_light_uv = (inverse_light_matrix * vec3(light_uv_interp.zw, 0.0)).xy; //for normal mapping - -#ifdef USE_SHADOWS - pos = outvec.xy; -#endif - - local_rot.xy = normalize((modelview_matrix * (extra_matrix_instance * vec4(1.0, 0.0, 0.0, 0.0))).xy); - local_rot.zw = normalize((modelview_matrix * (extra_matrix_instance * vec4(0.0, 1.0, 0.0, 0.0))).xy); -#ifdef USE_TEXTURE_RECT - local_rot.xy *= sign(src_rect.z); - local_rot.zw *= sign(src_rect.w); -#endif - -#endif -} - -/* clang-format off */ -[fragment] - -uniform mediump sampler2D color_texture; // texunit:0 -/* clang-format on */ -uniform highp vec2 color_texpixel_size; -uniform mediump sampler2D normal_texture; // texunit:1 - -in highp vec2 uv_interp; -in mediump vec4 color_interp; - -#if defined(SCREEN_TEXTURE_USED) - -uniform sampler2D screen_texture; // texunit:-3 - -#endif - -#if defined(SCREEN_UV_USED) - -uniform vec2 screen_pixel_size; -#endif - -layout(std140) uniform CanvasItemData { - - highp mat4 projection_matrix; - highp float time; -}; - -#ifdef USE_LIGHTING - -layout(std140) uniform LightData { - - highp mat4 light_matrix; - highp mat4 light_local_matrix; - highp mat4 shadow_matrix; - highp vec4 light_color; - highp vec4 light_shadow_color; - highp vec2 light_pos; - highp float shadowpixel_size; - highp float shadow_gradient; - highp float light_height; - highp float light_outside_alpha; - highp float shadow_distance_mult; -}; - -uniform lowp sampler2D light_texture; // texunit:-1 -in vec4 light_uv_interp; -in vec2 transformed_light_uv; - -in vec4 local_rot; - -#ifdef USE_SHADOWS - -uniform highp sampler2D shadow_texture; // texunit:-2 -in highp vec2 pos; - -#endif - -const bool at_light_pass = true; -#else -const bool at_light_pass = false; -#endif - -uniform mediump vec4 final_modulate; - -layout(location = 0) out mediump vec4 frag_color; - -#if defined(USE_MATERIAL) - -/* clang-format off */ -layout(std140) uniform UniformData { - -MATERIAL_UNIFORMS - -}; -/* clang-format on */ - -#endif - -/* clang-format off */ - -FRAGMENT_SHADER_GLOBALS - -/* clang-format on */ - -void light_compute( - inout vec4 light, - inout vec2 light_vec, - inout float light_height, - inout vec4 light_color, - vec2 light_uv, - inout vec4 shadow_color, - inout vec2 shadow_vec, - vec3 normal, - vec2 uv, -#if defined(SCREEN_UV_USED) - vec2 screen_uv, -#endif - vec4 color) { - -#if defined(USE_LIGHT_SHADER_CODE) - - /* clang-format off */ - -LIGHT_SHADER_CODE - - /* clang-format on */ - -#endif -} - -#ifdef USE_TEXTURE_RECT - -uniform vec4 dst_rect; -uniform vec4 src_rect; -uniform bool clip_rect_uv; - -#ifdef USE_NINEPATCH - -in highp vec2 pixel_size_interp; - -uniform int np_repeat_v; -uniform int np_repeat_h; -uniform bool np_draw_center; -// left top right bottom in pixel coordinates -uniform vec4 np_margins; - -float map_ninepatch_axis(float pixel, float draw_size, float tex_pixel_size, float margin_begin, float margin_end, float s_ratio, int np_repeat, inout int draw_center) { - - float tex_size = 1.0 / tex_pixel_size; - - float screen_margin_begin = margin_begin / s_ratio; - float screen_margin_end = margin_end / s_ratio; - if (pixel < screen_margin_begin) { - return pixel * s_ratio * tex_pixel_size; - } else if (pixel >= draw_size - screen_margin_end) { - return (tex_size - (draw_size - pixel) * s_ratio) * tex_pixel_size; - } else { - if (!np_draw_center) { - draw_center--; - } - - // np_repeat is passed as uniform using NinePatchRect::AxisStretchMode enum. - if (np_repeat == 0) { // Stretch. - // Convert to ratio. - float ratio = (pixel - screen_margin_begin) / (draw_size - screen_margin_begin - screen_margin_end); - // Scale to source texture. - return (margin_begin + ratio * (tex_size - margin_begin - margin_end)) * tex_pixel_size; - } else if (np_repeat == 1) { // Tile. - // Convert to offset. - float ofs = mod((pixel - screen_margin_begin), tex_size - margin_begin - margin_end); - // Scale to source texture. - return (margin_begin + ofs) * tex_pixel_size; - } else if (np_repeat == 2) { // Tile Fit. - // Calculate scale. - float src_area = draw_size - screen_margin_begin - screen_margin_end; - float dst_area = tex_size - margin_begin - margin_end; - float scale = max(1.0, floor(src_area / max(dst_area, 0.0000001) + 0.5)); - // Convert to ratio. - float ratio = (pixel - screen_margin_begin) / src_area; - ratio = mod(ratio * scale, 1.0); - // Scale to source texture. - return (margin_begin + ratio * dst_area) * tex_pixel_size; - } else { // Shouldn't happen, but silences compiler warning. - return 0.0; - } - } -} - -#endif -#endif - -uniform bool use_default_normal; - -void main() { - - vec4 color = color_interp; - vec2 uv = uv_interp; - -#ifdef USE_TEXTURE_RECT - -#ifdef USE_NINEPATCH - - int draw_center = 2; - float s_ratio = max((1.0 / color_texpixel_size.x) / abs(dst_rect.z), (1.0 / color_texpixel_size.y) / abs(dst_rect.w)); - s_ratio = max(1.0, s_ratio); - uv = vec2( - map_ninepatch_axis(pixel_size_interp.x, abs(dst_rect.z), color_texpixel_size.x, np_margins.x, np_margins.z, s_ratio, np_repeat_h, draw_center), - map_ninepatch_axis(pixel_size_interp.y, abs(dst_rect.w), color_texpixel_size.y, np_margins.y, np_margins.w, s_ratio, np_repeat_v, draw_center)); - - if (draw_center == 0) { - color.a = 0.0; - } - - uv = uv * src_rect.zw + src_rect.xy; //apply region if needed -#endif - - if (clip_rect_uv) { - - uv = clamp(uv, src_rect.xy, src_rect.xy + abs(src_rect.zw)); - } - -#endif - -#if !defined(COLOR_USED) - //default behavior, texture by color - -#ifdef USE_DISTANCE_FIELD - const float smoothing = 1.0 / 32.0; - float distance = textureLod(color_texture, uv, 0.0).a; - color.a = smoothstep(0.5 - smoothing, 0.5 + smoothing, distance) * color.a; -#else - color *= texture(color_texture, uv); - -#endif - -#endif - - vec3 normal; - -#if defined(NORMAL_USED) - - bool normal_used = true; -#else - bool normal_used = false; -#endif - - if (use_default_normal) { - normal.xy = textureLod(normal_texture, uv, 0.0).xy * 2.0 - 1.0; - normal.z = sqrt(1.0 - dot(normal.xy, normal.xy)); - normal_used = true; - } else { - normal = vec3(0.0, 0.0, 1.0); - } - -#if defined(SCREEN_UV_USED) - vec2 screen_uv = gl_FragCoord.xy * screen_pixel_size; -#endif - - { - float normal_depth = 1.0; - -#if defined(NORMALMAP_USED) - vec3 normal_map = vec3(0.0, 0.0, 1.0); - normal_used = true; -#endif - - /* clang-format off */ - -FRAGMENT_SHADER_CODE - - /* clang-format on */ - -#if defined(NORMALMAP_USED) - normal = mix(vec3(0.0, 0.0, 1.0), normal_map * vec3(2.0, -2.0, 1.0) - vec3(1.0, -1.0, 0.0), normal_depth); -#endif - } -#ifdef DEBUG_ENCODED_32 - highp float enc32 = dot(color, highp vec4(1.0 / (256.0 * 256.0 * 256.0), 1.0 / (256.0 * 256.0), 1.0 / 256.0, 1.0)); - color = vec4(vec3(enc32), 1.0); -#endif - - color *= final_modulate; - -#ifdef USE_LIGHTING - - vec2 light_vec = transformed_light_uv; - vec2 shadow_vec = transformed_light_uv; - - if (normal_used) { - normal.xy = mat2(local_rot.xy, local_rot.zw) * normal.xy; - } - - float att = 1.0; - - vec2 light_uv = light_uv_interp.xy; - vec4 light = texture(light_texture, light_uv); - - if (any(lessThan(light_uv_interp.xy, vec2(0.0, 0.0))) || any(greaterThanEqual(light_uv_interp.xy, vec2(1.0, 1.0)))) { - color.a *= light_outside_alpha; //invisible - - } else { - float real_light_height = light_height; - vec4 real_light_color = light_color; - vec4 real_light_shadow_color = light_shadow_color; - -#if defined(USE_LIGHT_SHADER_CODE) - //light is written by the light shader - light_compute( - light, - light_vec, - real_light_height, - real_light_color, - light_uv, - real_light_shadow_color, - shadow_vec, - normal, - uv, -#if defined(SCREEN_UV_USED) - screen_uv, -#endif - color); -#endif - - light *= real_light_color; - - if (normal_used) { - vec3 light_normal = normalize(vec3(light_vec, -real_light_height)); - light *= max(dot(-light_normal, normal), 0.0); - } - - color *= light; - -#ifdef USE_SHADOWS -#ifdef SHADOW_VEC_USED - mat3 inverse_light_matrix = mat3(light_matrix); - inverse_light_matrix[0] = normalize(inverse_light_matrix[0]); - inverse_light_matrix[1] = normalize(inverse_light_matrix[1]); - inverse_light_matrix[2] = normalize(inverse_light_matrix[2]); - shadow_vec = (mat3(inverse_light_matrix) * vec3(shadow_vec, 0.0)).xy; -#else - shadow_vec = light_uv_interp.zw; -#endif - float angle_to_light = -atan(shadow_vec.x, shadow_vec.y); - float PI = 3.14159265358979323846264; - /*int i = int(mod(floor((angle_to_light+7.0*PI/6.0)/(4.0*PI/6.0))+1.0, 3.0)); // +1 pq os indices estao em ordem 2,0,1 nos arrays - float ang*/ - - float su, sz; - - float abs_angle = abs(angle_to_light); - vec2 point; - float sh; - if (abs_angle < 45.0 * PI / 180.0) { - point = shadow_vec; - sh = 0.0 + (1.0 / 8.0); - } else if (abs_angle > 135.0 * PI / 180.0) { - point = -shadow_vec; - sh = 0.5 + (1.0 / 8.0); - } else if (angle_to_light > 0.0) { - - point = vec2(shadow_vec.y, -shadow_vec.x); - sh = 0.25 + (1.0 / 8.0); - } else { - - point = vec2(-shadow_vec.y, shadow_vec.x); - sh = 0.75 + (1.0 / 8.0); - } - - highp vec4 s = shadow_matrix * vec4(point, 0.0, 1.0); - s.xyz /= s.w; - su = s.x * 0.5 + 0.5; - sz = s.z * 0.5 + 0.5; - //sz=lightlength(light_vec); - - highp float shadow_attenuation = 0.0; - -#ifdef USE_RGBA_SHADOWS - -#define SHADOW_DEPTH(m_tex, m_uv) dot(texture((m_tex), (m_uv)), vec4(1.0 / (255.0 * 255.0 * 255.0), 1.0 / (255.0 * 255.0), 1.0 / 255.0, 1.0)) - -#else - -#define SHADOW_DEPTH(m_tex, m_uv) (texture((m_tex), (m_uv)).r) - -#endif - -#ifdef SHADOW_USE_GRADIENT - -#define SHADOW_TEST(m_ofs) \ - { \ - highp float sd = SHADOW_DEPTH(shadow_texture, vec2(m_ofs, sh)); \ - shadow_attenuation += 1.0 - smoothstep(sd, sd + shadow_gradient, sz); \ - } - -#else - -#define SHADOW_TEST(m_ofs) \ - { \ - highp float sd = SHADOW_DEPTH(shadow_texture, vec2(m_ofs, sh)); \ - shadow_attenuation += step(sz, sd); \ - } - -#endif - -#ifdef SHADOW_FILTER_NEAREST - - SHADOW_TEST(su); - -#endif - -#ifdef SHADOW_FILTER_PCF3 - - SHADOW_TEST(su + shadowpixel_size); - SHADOW_TEST(su); - SHADOW_TEST(su - shadowpixel_size); - shadow_attenuation /= 3.0; - -#endif - -#ifdef SHADOW_FILTER_PCF5 - - SHADOW_TEST(su + shadowpixel_size * 2.0); - SHADOW_TEST(su + shadowpixel_size); - SHADOW_TEST(su); - SHADOW_TEST(su - shadowpixel_size); - SHADOW_TEST(su - shadowpixel_size * 2.0); - shadow_attenuation /= 5.0; - -#endif - -#ifdef SHADOW_FILTER_PCF7 - - SHADOW_TEST(su + shadowpixel_size * 3.0); - SHADOW_TEST(su + shadowpixel_size * 2.0); - SHADOW_TEST(su + shadowpixel_size); - SHADOW_TEST(su); - SHADOW_TEST(su - shadowpixel_size); - SHADOW_TEST(su - shadowpixel_size * 2.0); - SHADOW_TEST(su - shadowpixel_size * 3.0); - shadow_attenuation /= 7.0; - -#endif - -#ifdef SHADOW_FILTER_PCF9 - - SHADOW_TEST(su + shadowpixel_size * 4.0); - SHADOW_TEST(su + shadowpixel_size * 3.0); - SHADOW_TEST(su + shadowpixel_size * 2.0); - SHADOW_TEST(su + shadowpixel_size); - SHADOW_TEST(su); - SHADOW_TEST(su - shadowpixel_size); - SHADOW_TEST(su - shadowpixel_size * 2.0); - SHADOW_TEST(su - shadowpixel_size * 3.0); - SHADOW_TEST(su - shadowpixel_size * 4.0); - shadow_attenuation /= 9.0; - -#endif - -#ifdef SHADOW_FILTER_PCF13 - - SHADOW_TEST(su + shadowpixel_size * 6.0); - SHADOW_TEST(su + shadowpixel_size * 5.0); - SHADOW_TEST(su + shadowpixel_size * 4.0); - SHADOW_TEST(su + shadowpixel_size * 3.0); - SHADOW_TEST(su + shadowpixel_size * 2.0); - SHADOW_TEST(su + shadowpixel_size); - SHADOW_TEST(su); - SHADOW_TEST(su - shadowpixel_size); - SHADOW_TEST(su - shadowpixel_size * 2.0); - SHADOW_TEST(su - shadowpixel_size * 3.0); - SHADOW_TEST(su - shadowpixel_size * 4.0); - SHADOW_TEST(su - shadowpixel_size * 5.0); - SHADOW_TEST(su - shadowpixel_size * 6.0); - shadow_attenuation /= 13.0; - -#endif - - //color *= shadow_attenuation; - color = mix(real_light_shadow_color, color, shadow_attenuation); -//use shadows -#endif - } - -//use lighting -#endif - //color.rgb *= color.a; - frag_color = color; -} diff --git a/drivers/gles3/shaders/canvas_shadow.glsl b/drivers/gles3/shaders/canvas_shadow.glsl deleted file mode 100644 index 4f706c5505..0000000000 --- a/drivers/gles3/shaders/canvas_shadow.glsl +++ /dev/null @@ -1,45 +0,0 @@ -/* clang-format off */ -[vertex] - -uniform highp mat4 projection_matrix; -/* clang-format on */ -uniform highp mat4 light_matrix; -uniform highp mat4 world_matrix; -uniform highp float distance_norm; - -layout(location = 0) in highp vec3 vertex; - -out highp vec4 position_interp; - -void main() { - - gl_Position = projection_matrix * (light_matrix * (world_matrix * vec4(vertex, 1.0))); - position_interp = gl_Position; -} - -/* clang-format off */ -[fragment] - -in highp vec4 position_interp; -/* clang-format on */ - -#ifdef USE_RGBA_SHADOWS -layout(location = 0) out lowp vec4 distance_buf; -#else -layout(location = 0) out highp float distance_buf; -#endif - -void main() { - - highp float depth = ((position_interp.z / position_interp.w) + 1.0) * 0.5 + 0.0; // bias - -#ifdef USE_RGBA_SHADOWS - - highp vec4 comp = fract(depth * vec4(255.0 * 255.0 * 255.0, 255.0 * 255.0, 255.0, 1.0)); - comp -= comp.xxyz * vec4(0.0, 1.0 / 255.0, 1.0 / 255.0, 1.0 / 255.0); - distance_buf = comp; -#else - - distance_buf = depth; -#endif -} diff --git a/drivers/gles3/shaders/copy.glsl b/drivers/gles3/shaders/copy.glsl deleted file mode 100644 index a3cdb3a543..0000000000 --- a/drivers/gles3/shaders/copy.glsl +++ /dev/null @@ -1,270 +0,0 @@ -/* clang-format off */ -[vertex] - -layout(location = 0) in highp vec4 vertex_attrib; -/* clang-format on */ -#if defined(USE_CUBEMAP) || defined(USE_PANORAMA) -layout(location = 4) in vec3 cube_in; -#else -layout(location = 4) in vec2 uv_in; -#endif -layout(location = 5) in vec2 uv2_in; - -#if defined(USE_CUBEMAP) || defined(USE_PANORAMA) -out vec3 cube_interp; -#else -out vec2 uv_interp; -#endif - -out vec2 uv2_interp; - -// These definitions are here because the shader-wrapper builder does -// not understand `#elif defined()` -#ifdef USE_DISPLAY_TRANSFORM -#endif - -#ifdef USE_COPY_SECTION - -uniform vec4 copy_section; - -#elif defined(USE_DISPLAY_TRANSFORM) - -uniform highp mat4 display_transform; - -#endif - -void main() { - -#if defined(USE_CUBEMAP) || defined(USE_PANORAMA) - cube_interp = cube_in; -#elif defined(USE_ASYM_PANO) - uv_interp = vertex_attrib.xy; -#else - uv_interp = uv_in; -#ifdef V_FLIP - uv_interp.y = 1.0 - uv_interp.y; -#endif - -#endif - uv2_interp = uv2_in; - gl_Position = vertex_attrib; - -#ifdef USE_COPY_SECTION - - uv_interp = copy_section.xy + uv_interp * copy_section.zw; - gl_Position.xy = (copy_section.xy + (gl_Position.xy * 0.5 + 0.5) * copy_section.zw) * 2.0 - 1.0; -#elif defined(USE_DISPLAY_TRANSFORM) - - uv_interp = (display_transform * vec4(uv_in, 1.0, 1.0)).xy; -#endif -} - -/* clang-format off */ -[fragment] - -#define M_PI 3.14159265359 - -#if !defined(USE_GLES_OVER_GL) -precision mediump float; -#endif - -#if defined(USE_CUBEMAP) || defined(USE_PANORAMA) -in vec3 cube_interp; -#else -in vec2 uv_interp; -#endif - -#ifdef USE_ASYM_PANO -uniform highp mat4 pano_transform; -uniform highp vec4 asym_proj; -#endif - -// These definitions are here because the shader-wrapper builder does -// not understand `#elif defined()` -#ifdef USE_TEXTURE3D -#endif -#ifdef USE_TEXTURE2DARRAY -#endif -#ifdef YCBCR_TO_SRGB -#endif - -#ifdef USE_CUBEMAP -uniform samplerCube source_cube; //texunit:0 -#elif defined(USE_TEXTURE3D) -uniform sampler3D source_3d; //texunit:0 -#elif defined(USE_TEXTURE2DARRAY) -uniform sampler2DArray source_2d_array; //texunit:0 -#else -uniform sampler2D source; //texunit:0 -#endif - -#ifdef SEP_CBCR_TEXTURE -uniform sampler2D CbCr; //texunit:1 -#endif - -/* clang-format on */ - -#ifdef USE_LOD -uniform float mip_level; -#endif - -#if defined(USE_TEXTURE3D) || defined(USE_TEXTURE2DARRAY) -uniform float layer; -#endif - -#ifdef USE_MULTIPLIER -uniform float multiplier; -#endif - -#if defined(USE_PANORAMA) || defined(USE_ASYM_PANO) -uniform highp mat4 sky_transform; - -vec4 texturePanorama(vec3 normal, sampler2D pano) { - - vec2 st = vec2( - atan(normal.x, normal.z), - acos(normal.y)); - - if (st.x < 0.0) - st.x += M_PI * 2.0; - - st /= vec2(M_PI * 2.0, M_PI); - - return textureLod(pano, st, 0.0); -} - -#endif - -uniform vec2 pixel_size; - -in vec2 uv2_interp; - -#ifdef USE_BCS - -uniform vec3 bcs; - -#endif - -#ifdef USE_COLOR_CORRECTION - -uniform sampler2D color_correction; //texunit:1 - -#endif - -layout(location = 0) out vec4 frag_color; - -void main() { - - //vec4 color = color_interp; - -#ifdef USE_PANORAMA - - vec3 cube_normal = normalize(cube_interp); - cube_normal.z = -cube_normal.z; - cube_normal = mat3(sky_transform) * cube_normal; - cube_normal.z = -cube_normal.z; - - vec4 color = texturePanorama(cube_normal, source); - -#elif defined(USE_ASYM_PANO) - - // When an asymmetrical projection matrix is used (applicable for stereoscopic rendering i.e. VR) we need to do this calculation per fragment to get a perspective correct result. - // Asymmetrical projection means the center of projection is no longer in the center of the screen but shifted. - // The Matrix[2][0] (= asym_proj.x) and Matrix[2][1] (= asym_proj.z) values are what provide the right shift in the image. - - vec3 cube_normal; - cube_normal.z = -1.0; - cube_normal.x = (cube_normal.z * (-uv_interp.x - asym_proj.x)) / asym_proj.y; - cube_normal.y = (cube_normal.z * (-uv_interp.y - asym_proj.z)) / asym_proj.a; - cube_normal = mat3(sky_transform) * mat3(pano_transform) * cube_normal; - cube_normal.z = -cube_normal.z; - - vec4 color = texturePanorama(normalize(cube_normal.xyz), source); - -#elif defined(USE_CUBEMAP) - vec4 color = texture(source_cube, normalize(cube_interp)); - -#elif defined(USE_TEXTURE3D) - vec4 color = textureLod(source_3d, vec3(uv_interp, layer), 0.0); -#elif defined(USE_TEXTURE2DARRAY) - vec4 color = textureLod(source_2d_array, vec3(uv_interp, layer), 0.0); -#elif defined(SEP_CBCR_TEXTURE) - vec4 color; - color.r = textureLod(source, uv_interp, 0.0).r; - color.gb = textureLod(CbCr, uv_interp, 0.0).rg - vec2(0.5, 0.5); - color.a = 1.0; -#else -#ifdef USE_LOD - vec4 color = textureLod(source, uv_interp, mip_level); -#else - vec4 color = textureLod(source, uv_interp, 0.0); -#endif -#endif - -#ifdef LINEAR_TO_SRGB - // regular Linear -> SRGB conversion - vec3 a = vec3(0.055); - color.rgb = mix((vec3(1.0) + a) * pow(color.rgb, vec3(1.0 / 2.4)) - a, 12.92 * color.rgb, lessThan(color.rgb, vec3(0.0031308))); - -#elif defined(YCBCR_TO_SRGB) - - // YCbCr -> SRGB conversion - // Using BT.709 which is the standard for HDTV - color.rgb = mat3( - vec3(1.00000, 1.00000, 1.00000), - vec3(0.00000, -0.18732, 1.85560), - vec3(1.57481, -0.46813, 0.00000)) * - color.rgb; - -#endif - -#ifdef SRGB_TO_LINEAR - - color.rgb = mix(pow((color.rgb + vec3(0.055)) * (1.0 / (1.0 + 0.055)), vec3(2.4)), color.rgb * (1.0 / 12.92), lessThan(color.rgb, vec3(0.04045))); -#endif - -#ifdef DEBUG_GRADIENT - color.rg = uv_interp; - color.b = 0.0; -#endif - -#ifdef DISABLE_ALPHA - color.a = 1.0; -#endif - -#ifdef GAUSSIAN_HORIZONTAL - color *= 0.38774; - color += texture(source, uv_interp + vec2(1.0, 0.0) * pixel_size) * 0.24477; - color += texture(source, uv_interp + vec2(2.0, 0.0) * pixel_size) * 0.06136; - color += texture(source, uv_interp + vec2(-1.0, 0.0) * pixel_size) * 0.24477; - color += texture(source, uv_interp + vec2(-2.0, 0.0) * pixel_size) * 0.06136; -#endif - -#ifdef GAUSSIAN_VERTICAL - color *= 0.38774; - color += texture(source, uv_interp + vec2(0.0, 1.0) * pixel_size) * 0.24477; - color += texture(source, uv_interp + vec2(0.0, 2.0) * pixel_size) * 0.06136; - color += texture(source, uv_interp + vec2(0.0, -1.0) * pixel_size) * 0.24477; - color += texture(source, uv_interp + vec2(0.0, -2.0) * pixel_size) * 0.06136; -#endif - -#ifdef USE_BCS - - color.rgb = mix(vec3(0.0), color.rgb, bcs.x); - color.rgb = mix(vec3(0.5), color.rgb, bcs.y); - color.rgb = mix(vec3(dot(vec3(1.0), color.rgb) * 0.33333), color.rgb, bcs.z); - -#endif - -#ifdef USE_COLOR_CORRECTION - - color.r = texture(color_correction, vec2(color.r, 0.0)).r; - color.g = texture(color_correction, vec2(color.g, 0.0)).g; - color.b = texture(color_correction, vec2(color.b, 0.0)).b; -#endif - -#ifdef USE_MULTIPLIER - color.rgb *= multiplier; -#endif - frag_color = color; -} diff --git a/drivers/gles3/shaders/cube_to_dp.glsl b/drivers/gles3/shaders/cube_to_dp.glsl deleted file mode 100644 index 2b74f054f9..0000000000 --- a/drivers/gles3/shaders/cube_to_dp.glsl +++ /dev/null @@ -1,79 +0,0 @@ -/* clang-format off */ -[vertex] - -layout(location = 0) in highp vec4 vertex_attrib; -/* clang-format on */ -layout(location = 4) in vec2 uv_in; - -out vec2 uv_interp; - -void main() { - - uv_interp = uv_in; - gl_Position = vertex_attrib; -} - -/* clang-format off */ -[fragment] - -uniform highp samplerCube source_cube; //texunit:0 -/* clang-format on */ -in vec2 uv_interp; - -uniform bool z_flip; -uniform highp float z_far; -uniform highp float z_near; -uniform highp float bias; - -void main() { - - highp vec3 normal = vec3(uv_interp * 2.0 - 1.0, 0.0); - /* - if (z_flip) { - normal.z = 0.5 - 0.5 * ((normal.x * normal.x) + (normal.y * normal.y)); - } else { - normal.z = -0.5 + 0.5 * ((normal.x * normal.x) + (normal.y * normal.y)); - } - */ - - //normal.z = sqrt(1.0 - dot(normal.xy, normal.xy)); - //normal.xy *= 1.0 + normal.z; - - normal.z = 0.5 - 0.5 * ((normal.x * normal.x) + (normal.y * normal.y)); - normal = normalize(normal); - /* - normal.z = 0.5; - normal = normalize(normal); - */ - - if (!z_flip) { - normal.z = -normal.z; - } - - //normal = normalize(vec3(uv_interp * 2.0 - 1.0, 1.0)); - float depth = texture(source_cube, normal).r; - - // absolute values for direction cosines, bigger value equals closer to basis axis - vec3 unorm = abs(normal); - - if ((unorm.x >= unorm.y) && (unorm.x >= unorm.z)) { - // x code - unorm = normal.x > 0.0 ? vec3(1.0, 0.0, 0.0) : vec3(-1.0, 0.0, 0.0); - } else if ((unorm.y > unorm.x) && (unorm.y >= unorm.z)) { - // y code - unorm = normal.y > 0.0 ? vec3(0.0, 1.0, 0.0) : vec3(0.0, -1.0, 0.0); - } else if ((unorm.z > unorm.x) && (unorm.z > unorm.y)) { - // z code - unorm = normal.z > 0.0 ? vec3(0.0, 0.0, 1.0) : vec3(0.0, 0.0, -1.0); - } else { - // oh-no we messed up code - // has to be - unorm = vec3(1.0, 0.0, 0.0); - } - - float depth_fix = 1.0 / dot(normal, unorm); - - depth = 2.0 * depth - 1.0; - float linear_depth = 2.0 * z_near * z_far / (z_far + z_near - depth * (z_far - z_near)); - gl_FragDepth = (linear_depth * depth_fix + bias) / z_far; -} diff --git a/drivers/gles3/shaders/cubemap_filter.glsl b/drivers/gles3/shaders/cubemap_filter.glsl deleted file mode 100644 index e1872eb433..0000000000 --- a/drivers/gles3/shaders/cubemap_filter.glsl +++ /dev/null @@ -1,370 +0,0 @@ -/* clang-format off */ -[vertex] - -layout(location = 0) in highp vec2 vertex; -/* clang-format on */ - -layout(location = 4) in highp vec2 uv; - -out highp vec2 uv_interp; - -void main() { - - uv_interp = uv; - gl_Position = vec4(vertex, 0, 1); -} - -/* clang-format off */ -[fragment] - -precision highp float; -/* clang-format on */ -precision highp int; - -#ifdef USE_SOURCE_PANORAMA -uniform sampler2D source_panorama; //texunit:0 -uniform float source_resolution; -#endif - -#ifdef USE_SOURCE_DUAL_PARABOLOID_ARRAY -uniform sampler2DArray source_dual_paraboloid_array; //texunit:0 -uniform int source_array_index; -#endif - -#ifdef USE_SOURCE_DUAL_PARABOLOID -uniform sampler2D source_dual_paraboloid; //texunit:0 -#endif - -#if defined(USE_SOURCE_DUAL_PARABOLOID) || defined(COMPUTE_IRRADIANCE) -uniform float source_mip_level; -#endif - -#if !defined(USE_SOURCE_DUAL_PARABOLOID_ARRAY) && !defined(USE_SOURCE_PANORAMA) && !defined(USE_SOURCE_DUAL_PARABOLOID) -uniform samplerCube source_cube; //texunit:0 -#endif - -uniform int face_id; -uniform float roughness; - -in highp vec2 uv_interp; - -layout(location = 0) out vec4 frag_color; - -#define M_PI 3.14159265359 - -vec3 texelCoordToVec(vec2 uv, int faceID) { - mat3 faceUvVectors[6]; - /* - // -x - faceUvVectors[1][0] = vec3(0.0, 0.0, 1.0); // u -> +z - faceUvVectors[1][1] = vec3(0.0, -1.0, 0.0); // v -> -y - faceUvVectors[1][2] = vec3(-1.0, 0.0, 0.0); // -x face - - // +x - faceUvVectors[0][0] = vec3(0.0, 0.0, -1.0); // u -> -z - faceUvVectors[0][1] = vec3(0.0, -1.0, 0.0); // v -> -y - faceUvVectors[0][2] = vec3(1.0, 0.0, 0.0); // +x face - - // -y - faceUvVectors[3][0] = vec3(1.0, 0.0, 0.0); // u -> +x - faceUvVectors[3][1] = vec3(0.0, 0.0, -1.0); // v -> -z - faceUvVectors[3][2] = vec3(0.0, -1.0, 0.0); // -y face - - // +y - faceUvVectors[2][0] = vec3(1.0, 0.0, 0.0); // u -> +x - faceUvVectors[2][1] = vec3(0.0, 0.0, 1.0); // v -> +z - faceUvVectors[2][2] = vec3(0.0, 1.0, 0.0); // +y face - - // -z - faceUvVectors[5][0] = vec3(-1.0, 0.0, 0.0); // u -> -x - faceUvVectors[5][1] = vec3(0.0, -1.0, 0.0); // v -> -y - faceUvVectors[5][2] = vec3(0.0, 0.0, -1.0); // -z face - - // +z - faceUvVectors[4][0] = vec3(1.0, 0.0, 0.0); // u -> +x - faceUvVectors[4][1] = vec3(0.0, -1.0, 0.0); // v -> -y - faceUvVectors[4][2] = vec3(0.0, 0.0, 1.0); // +z face - */ - - // -x - faceUvVectors[0][0] = vec3(0.0, 0.0, 1.0); // u -> +z - faceUvVectors[0][1] = vec3(0.0, -1.0, 0.0); // v -> -y - faceUvVectors[0][2] = vec3(-1.0, 0.0, 0.0); // -x face - - // +x - faceUvVectors[1][0] = vec3(0.0, 0.0, -1.0); // u -> -z - faceUvVectors[1][1] = vec3(0.0, -1.0, 0.0); // v -> -y - faceUvVectors[1][2] = vec3(1.0, 0.0, 0.0); // +x face - - // -y - faceUvVectors[2][0] = vec3(1.0, 0.0, 0.0); // u -> +x - faceUvVectors[2][1] = vec3(0.0, 0.0, -1.0); // v -> -z - faceUvVectors[2][2] = vec3(0.0, -1.0, 0.0); // -y face - - // +y - faceUvVectors[3][0] = vec3(1.0, 0.0, 0.0); // u -> +x - faceUvVectors[3][1] = vec3(0.0, 0.0, 1.0); // v -> +z - faceUvVectors[3][2] = vec3(0.0, 1.0, 0.0); // +y face - - // -z - faceUvVectors[4][0] = vec3(-1.0, 0.0, 0.0); // u -> -x - faceUvVectors[4][1] = vec3(0.0, -1.0, 0.0); // v -> -y - faceUvVectors[4][2] = vec3(0.0, 0.0, -1.0); // -z face - - // +z - faceUvVectors[5][0] = vec3(1.0, 0.0, 0.0); // u -> +x - faceUvVectors[5][1] = vec3(0.0, -1.0, 0.0); // v -> -y - faceUvVectors[5][2] = vec3(0.0, 0.0, 1.0); // +z face - - // out = u * s_faceUv[0] + v * s_faceUv[1] + s_faceUv[2]. - vec3 result = (faceUvVectors[faceID][0] * uv.x) + (faceUvVectors[faceID][1] * uv.y) + faceUvVectors[faceID][2]; - return normalize(result); -} - -vec3 ImportanceSampleGGX(vec2 Xi, float Roughness, vec3 N) { - float a = Roughness * Roughness; // DISNEY'S ROUGHNESS [see Burley'12 siggraph] - - // Compute distribution direction - float Phi = 2.0 * M_PI * Xi.x; - float CosTheta = sqrt((1.0 - Xi.y) / (1.0 + (a * a - 1.0) * Xi.y)); - float SinTheta = sqrt(1.0 - CosTheta * CosTheta); - - // Convert to spherical direction - vec3 H; - H.x = SinTheta * cos(Phi); - H.y = SinTheta * sin(Phi); - H.z = CosTheta; - - vec3 UpVector = abs(N.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0); - vec3 TangentX = normalize(cross(UpVector, N)); - vec3 TangentY = cross(N, TangentX); - - // Tangent to world space - return TangentX * H.x + TangentY * H.y + N * H.z; -} - -float DistributionGGX(vec3 N, vec3 H, float roughness) { - float a = roughness * roughness; - float a2 = a * a; - float NdotH = max(dot(N, H), 0.0); - float NdotH2 = NdotH * NdotH; - - float nom = a2; - float denom = (NdotH2 * (a2 - 1.0) + 1.0); - denom = M_PI * denom * denom; - - return nom / denom; -} - -// http://graphicrants.blogspot.com.au/2013/08/specular-brdf-reference.html -float GGX(float NdotV, float a) { - float k = a / 2.0; - return NdotV / (NdotV * (1.0 - k) + k); -} - -// http://graphicrants.blogspot.com.au/2013/08/specular-brdf-reference.html -float G_Smith(float a, float nDotV, float nDotL) { - return GGX(nDotL, a * a) * GGX(nDotV, a * a); -} - -float radicalInverse_VdC(uint bits) { - bits = (bits << 16u) | (bits >> 16u); - bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u); - bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u); - bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u); - bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u); - return float(bits) * 2.3283064365386963e-10; // / 0x100000000 -} - -vec2 Hammersley(uint i, uint N) { - return vec2(float(i) / float(N), radicalInverse_VdC(i)); -} - -#ifdef LOW_QUALITY - -#define SAMPLE_COUNT 64u -#define SAMPLE_DELTA 0.1 - -#else - -#define SAMPLE_COUNT 512u -#define SAMPLE_DELTA 0.03 - -#endif - -uniform bool z_flip; - -#ifdef USE_SOURCE_PANORAMA - -vec4 texturePanorama(vec3 normal, sampler2D pano, float mipLevel) { - - vec2 st = vec2( - atan(normal.x, normal.z), - acos(normal.y)); - - if (st.x < 0.0) - st.x += M_PI * 2.0; - - st /= vec2(M_PI * 2.0, M_PI); - - return textureLod(pano, st, mipLevel); -} - -#endif - -#ifdef USE_SOURCE_DUAL_PARABOLOID_ARRAY - -vec4 textureDualParaboloidArray(vec3 normal) { - - vec3 norm = normalize(normal); - norm.xy /= 1.0 + abs(norm.z); - norm.xy = norm.xy * vec2(0.5, 0.25) + vec2(0.5, 0.25); - if (norm.z < 0.0) { - norm.y = 0.5 - norm.y + 0.5; - } - return textureLod(source_dual_paraboloid_array, vec3(norm.xy, float(source_array_index)), 0.0); -} - -#endif - -#ifdef USE_SOURCE_DUAL_PARABOLOID -vec4 textureDualParaboloid(vec3 normal) { - - vec3 norm = normalize(normal); - norm.xy /= 1.0 + abs(norm.z); - norm.xy = norm.xy * vec2(0.5, 0.25) + vec2(0.5, 0.25); - if (norm.z < 0.0) { - norm.y = 0.5 - norm.y + 0.5; - } - return textureLod(source_dual_paraboloid, norm.xy, source_mip_level); -} - -#endif - -void main() { - -#ifdef USE_DUAL_PARABOLOID - - vec3 N = vec3(uv_interp * 2.0 - 1.0, 0.0); - N.z = 0.5 - 0.5 * ((N.x * N.x) + (N.y * N.y)); - N = normalize(N); - - if (z_flip) { - N.y = -N.y; //y is flipped to improve blending between both sides - N.z = -N.z; - } - -#else - vec2 uv = (uv_interp * 2.0) - 1.0; - vec3 N = texelCoordToVec(uv, face_id); -#endif - //vec4 color = color_interp; - -#ifdef USE_DIRECT_WRITE - -#ifdef USE_SOURCE_PANORAMA - - frag_color = vec4(texturePanorama(N, source_panorama, 0.0).rgb, 1.0); -#endif - -#ifdef USE_SOURCE_DUAL_PARABOLOID_ARRAY - - frag_color = vec4(textureDualParaboloidArray(N).rgb, 1.0); -#endif - -#ifdef USE_SOURCE_DUAL_PARABOLOID - - frag_color = vec4(textureDualParaboloid(N).rgb, 1.0); -#endif - -#if !defined(USE_SOURCE_DUAL_PARABOLOID_ARRAY) && !defined(USE_SOURCE_PANORAMA) && !defined(USE_SOURCE_DUAL_PARABOLOID) - - N.y = -N.y; - frag_color = vec4(texture(N, source_cube).rgb, 1.0); -#endif - -#else // USE_DIRECT_WRITE - -#ifdef COMPUTE_IRRADIANCE - - vec3 irradiance = vec3(0.0); - - // tangent space calculation from origin point - vec3 UpVector = vec3(0.0, 1.0, 0.0); - vec3 TangentX = cross(UpVector, N); - vec3 TangentY = cross(N, TangentX); - - float num_samples = 0.0f; - - for (float phi = 0.0; phi < 2.0 * M_PI; phi += SAMPLE_DELTA) { - for (float theta = 0.0; theta < 0.5 * M_PI; theta += SAMPLE_DELTA) { - // Calculate sample positions - vec3 tangentSample = vec3(sin(theta) * cos(phi), sin(theta) * sin(phi), cos(theta)); - // Find world vector of sample position - vec3 H = tangentSample.x * TangentX + tangentSample.y * TangentY + tangentSample.z * N; - - vec2 st = vec2(atan(H.x, H.z), acos(H.y)); - if (st.x < 0.0) { - st.x += M_PI * 2.0; - } - st /= vec2(M_PI * 2.0, M_PI); - - irradiance += textureLod(source_panorama, st, source_mip_level).rgb * cos(theta) * sin(theta); - num_samples++; - } - } - irradiance = M_PI * irradiance * (1.0 / float(num_samples)); - - frag_color = vec4(irradiance, 1.0); - -#else - - vec4 sum = vec4(0.0, 0.0, 0.0, 0.0); - - for (uint sampleNum = 0u; sampleNum < SAMPLE_COUNT; sampleNum++) { - vec2 xi = Hammersley(sampleNum, SAMPLE_COUNT); - - vec3 H = normalize(ImportanceSampleGGX(xi, roughness, N)); - vec3 V = N; - vec3 L = normalize(2.0 * dot(V, H) * H - V); - - float ndotl = max(dot(N, L), 0.0); - - if (ndotl > 0.0) { - -#ifdef USE_SOURCE_PANORAMA - float D = DistributionGGX(N, H, roughness); - float ndoth = max(dot(N, H), 0.0); - float hdotv = max(dot(H, V), 0.0); - float pdf = D * ndoth / (4.0 * hdotv) + 0.0001; - - float saTexel = 4.0 * M_PI / (6.0 * source_resolution * source_resolution); - float saSample = 1.0 / (float(SAMPLE_COUNT) * pdf + 0.0001); - - float mipLevel = roughness == 0.0 ? 0.0 : 0.5 * log2(saSample / saTexel); - - sum.rgb += texturePanorama(L, source_panorama, mipLevel).rgb * ndotl; -#endif - -#ifdef USE_SOURCE_DUAL_PARABOLOID_ARRAY - sum.rgb += textureDualParaboloidArray(L).rgb * ndotl; -#endif - -#ifdef USE_SOURCE_DUAL_PARABOLOID - sum.rgb += textureDualParaboloid(L).rgb * ndotl; -#endif - -#if !defined(USE_SOURCE_DUAL_PARABOLOID_ARRAY) && !defined(USE_SOURCE_PANORAMA) && !defined(USE_SOURCE_DUAL_PARABOLOID) - L.y = -L.y; - sum.rgb += textureLod(source_cube, L, 0.0).rgb * ndotl; -#endif - sum.a += ndotl; - } - } - sum /= sum.a; - - frag_color = vec4(sum.rgb, 1.0); - -#endif // COMPUTE_IRRADIANCE -#endif // USE_DIRECT_WRITE -} diff --git a/drivers/gles3/shaders/effect_blur.glsl b/drivers/gles3/shaders/effect_blur.glsl deleted file mode 100644 index ff5a9f326f..0000000000 --- a/drivers/gles3/shaders/effect_blur.glsl +++ /dev/null @@ -1,293 +0,0 @@ -/* clang-format off */ -[vertex] - -layout(location = 0) in highp vec4 vertex_attrib; -/* clang-format on */ -layout(location = 4) in vec2 uv_in; - -out vec2 uv_interp; - -#ifdef USE_BLUR_SECTION - -uniform vec4 blur_section; - -#endif - -void main() { - - uv_interp = uv_in; - gl_Position = vertex_attrib; -#ifdef USE_BLUR_SECTION - - uv_interp = blur_section.xy + uv_interp * blur_section.zw; - gl_Position.xy = (blur_section.xy + (gl_Position.xy * 0.5 + 0.5) * blur_section.zw) * 2.0 - 1.0; -#endif -} - -/* clang-format off */ -[fragment] - -#if !defined(GLES_OVER_GL) -precision mediump float; -#endif -/* clang-format on */ - -in vec2 uv_interp; -uniform sampler2D source_color; //texunit:0 - -#ifdef SSAO_MERGE -uniform sampler2D source_ssao; //texunit:1 -#endif - -uniform float lod; -uniform vec2 pixel_size; - -layout(location = 0) out vec4 frag_color; - -#ifdef SSAO_MERGE - -uniform vec4 ssao_color; - -#endif - -#if defined(GLOW_GAUSSIAN_HORIZONTAL) || defined(GLOW_GAUSSIAN_VERTICAL) - -uniform float glow_strength; - -#endif - -#if defined(DOF_FAR_BLUR) || defined(DOF_NEAR_BLUR) - -#ifdef DOF_QUALITY_LOW -const int dof_kernel_size = 5; -const int dof_kernel_from = 2; -const float dof_kernel[5] = float[](0.153388, 0.221461, 0.250301, 0.221461, 0.153388); -#endif - -#ifdef DOF_QUALITY_MEDIUM -const int dof_kernel_size = 11; -const int dof_kernel_from = 5; -const float dof_kernel[11] = float[](0.055037, 0.072806, 0.090506, 0.105726, 0.116061, 0.119726, 0.116061, 0.105726, 0.090506, 0.072806, 0.055037); - -#endif - -#ifdef DOF_QUALITY_HIGH -const int dof_kernel_size = 21; -const int dof_kernel_from = 10; -const float dof_kernel[21] = float[](0.028174, 0.032676, 0.037311, 0.041944, 0.046421, 0.050582, 0.054261, 0.057307, 0.059587, 0.060998, 0.061476, 0.060998, 0.059587, 0.057307, 0.054261, 0.050582, 0.046421, 0.041944, 0.037311, 0.032676, 0.028174); -#endif - -uniform sampler2D dof_source_depth; //texunit:1 -uniform float dof_begin; -uniform float dof_end; -uniform vec2 dof_dir; -uniform float dof_radius; - -#ifdef DOF_NEAR_BLUR_MERGE - -uniform sampler2D source_dof_original; //texunit:2 -#endif - -#endif - -#ifdef GLOW_FIRST_PASS - -uniform float exposure; -uniform float white; -uniform highp float luminance_cap; - -#ifdef GLOW_USE_AUTO_EXPOSURE - -uniform highp sampler2D source_auto_exposure; //texunit:1 -uniform highp float auto_exposure_grey; - -#endif - -uniform float glow_bloom; -uniform float glow_hdr_threshold; -uniform float glow_hdr_scale; - -#endif - -uniform float camera_z_far; -uniform float camera_z_near; - -void main() { - -#ifdef GAUSSIAN_HORIZONTAL - vec2 pix_size = pixel_size; - pix_size *= 0.5; //reading from larger buffer, so use more samples - // sigma 2 - vec4 color = textureLod(source_color, uv_interp + vec2(0.0, 0.0) * pix_size, lod) * 0.214607; - color += textureLod(source_color, uv_interp + vec2(1.0, 0.0) * pix_size, lod) * 0.189879; - color += textureLod(source_color, uv_interp + vec2(2.0, 0.0) * pix_size, lod) * 0.131514; - color += textureLod(source_color, uv_interp + vec2(3.0, 0.0) * pix_size, lod) * 0.071303; - color += textureLod(source_color, uv_interp + vec2(-1.0, 0.0) * pix_size, lod) * 0.189879; - color += textureLod(source_color, uv_interp + vec2(-2.0, 0.0) * pix_size, lod) * 0.131514; - color += textureLod(source_color, uv_interp + vec2(-3.0, 0.0) * pix_size, lod) * 0.071303; - frag_color = color; -#endif - -#ifdef GAUSSIAN_VERTICAL - vec4 color = textureLod(source_color, uv_interp + vec2(0.0, 0.0) * pixel_size, lod) * 0.38774; - color += textureLod(source_color, uv_interp + vec2(0.0, 1.0) * pixel_size, lod) * 0.24477; - color += textureLod(source_color, uv_interp + vec2(0.0, 2.0) * pixel_size, lod) * 0.06136; - color += textureLod(source_color, uv_interp + vec2(0.0, -1.0) * pixel_size, lod) * 0.24477; - color += textureLod(source_color, uv_interp + vec2(0.0, -2.0) * pixel_size, lod) * 0.06136; - frag_color = color; -#endif - - //glow uses larger sigma for a more rounded blur effect - -#ifdef GLOW_GAUSSIAN_HORIZONTAL - vec2 pix_size = pixel_size; - pix_size *= 0.5; //reading from larger buffer, so use more samples - vec4 color = textureLod(source_color, uv_interp + vec2(0.0, 0.0) * pix_size, lod) * 0.174938; - color += textureLod(source_color, uv_interp + vec2(1.0, 0.0) * pix_size, lod) * 0.165569; - color += textureLod(source_color, uv_interp + vec2(2.0, 0.0) * pix_size, lod) * 0.140367; - color += textureLod(source_color, uv_interp + vec2(3.0, 0.0) * pix_size, lod) * 0.106595; - color += textureLod(source_color, uv_interp + vec2(-1.0, 0.0) * pix_size, lod) * 0.165569; - color += textureLod(source_color, uv_interp + vec2(-2.0, 0.0) * pix_size, lod) * 0.140367; - color += textureLod(source_color, uv_interp + vec2(-3.0, 0.0) * pix_size, lod) * 0.106595; - color *= glow_strength; - frag_color = color; -#endif - -#ifdef GLOW_GAUSSIAN_VERTICAL - vec4 color = textureLod(source_color, uv_interp + vec2(0.0, 0.0) * pixel_size, lod) * 0.288713; - color += textureLod(source_color, uv_interp + vec2(0.0, 1.0) * pixel_size, lod) * 0.233062; - color += textureLod(source_color, uv_interp + vec2(0.0, 2.0) * pixel_size, lod) * 0.122581; - color += textureLod(source_color, uv_interp + vec2(0.0, -1.0) * pixel_size, lod) * 0.233062; - color += textureLod(source_color, uv_interp + vec2(0.0, -2.0) * pixel_size, lod) * 0.122581; - color *= glow_strength; - frag_color = color; -#endif - -#ifdef DOF_FAR_BLUR - - vec4 color_accum = vec4(0.0); - - float depth = textureLod(dof_source_depth, uv_interp, 0.0).r; - depth = depth * 2.0 - 1.0; -#ifdef USE_ORTHOGONAL_PROJECTION - depth = ((depth + (camera_z_far + camera_z_near) / (camera_z_far - camera_z_near)) * (camera_z_far - camera_z_near)) / 2.0; -#else - depth = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - depth * (camera_z_far - camera_z_near)); -#endif - - float amount = smoothstep(dof_begin, dof_end, depth); - float k_accum = 0.0; - - for (int i = 0; i < dof_kernel_size; i++) { - - int int_ofs = i - dof_kernel_from; - vec2 tap_uv = uv_interp + dof_dir * float(int_ofs) * amount * dof_radius; - - float tap_k = dof_kernel[i]; - - float tap_depth = texture(dof_source_depth, tap_uv, 0.0).r; - tap_depth = tap_depth * 2.0 - 1.0; -#ifdef USE_ORTHOGONAL_PROJECTION - tap_depth = ((tap_depth + (camera_z_far + camera_z_near) / (camera_z_far - camera_z_near)) * (camera_z_far - camera_z_near)) / 2.0; -#else - tap_depth = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - tap_depth * (camera_z_far - camera_z_near)); -#endif - float tap_amount = mix(smoothstep(dof_begin, dof_end, tap_depth), 1.0, int_ofs == 0); - tap_amount *= tap_amount * tap_amount; //prevent undesired glow effect - - vec4 tap_color = textureLod(source_color, tap_uv, 0.0) * tap_k; - - k_accum += tap_k * tap_amount; - color_accum += tap_color * tap_amount; - } - - if (k_accum > 0.0) { - color_accum /= k_accum; - } - - frag_color = color_accum; ///k_accum; - -#endif - -#ifdef DOF_NEAR_BLUR - - vec4 color_accum = vec4(0.0); - - float max_accum = 0.0; - - for (int i = 0; i < dof_kernel_size; i++) { - - int int_ofs = i - dof_kernel_from; - vec2 tap_uv = uv_interp + dof_dir * float(int_ofs) * dof_radius; - float ofs_influence = max(0.0, 1.0 - float(abs(int_ofs)) / float(dof_kernel_from)); - - float tap_k = dof_kernel[i]; - - vec4 tap_color = textureLod(source_color, tap_uv, 0.0); - - float tap_depth = texture(dof_source_depth, tap_uv, 0.0).r; - tap_depth = tap_depth * 2.0 - 1.0; -#ifdef USE_ORTHOGONAL_PROJECTION - tap_depth = ((tap_depth + (camera_z_far + camera_z_near) / (camera_z_far - camera_z_near)) * (camera_z_far - camera_z_near)) / 2.0; -#else - tap_depth = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - tap_depth * (camera_z_far - camera_z_near)); -#endif - float tap_amount = 1.0 - smoothstep(dof_end, dof_begin, tap_depth); - tap_amount *= tap_amount * tap_amount; //prevent undesired glow effect - -#ifdef DOF_NEAR_FIRST_TAP - - tap_color.a = 1.0 - smoothstep(dof_end, dof_begin, tap_depth); - -#endif - - max_accum = max(max_accum, tap_amount * ofs_influence); - - color_accum += tap_color * tap_k; - } - - color_accum.a = max(color_accum.a, sqrt(max_accum)); - -#ifdef DOF_NEAR_BLUR_MERGE - - vec4 original = textureLod(source_dof_original, uv_interp, 0.0); - color_accum = mix(original, color_accum, color_accum.a); - -#endif - -#ifndef DOF_NEAR_FIRST_TAP - //color_accum=vec4(vec3(color_accum.a),1.0); -#endif - frag_color = color_accum; - -#endif - -#ifdef GLOW_FIRST_PASS - -#ifdef GLOW_USE_AUTO_EXPOSURE - - frag_color /= texelFetch(source_auto_exposure, ivec2(0, 0), 0).r / auto_exposure_grey; -#endif - frag_color *= exposure; - - float luminance = max(frag_color.r, max(frag_color.g, frag_color.b)); - float feedback = max(smoothstep(glow_hdr_threshold, glow_hdr_threshold + glow_hdr_scale, luminance), glow_bloom); - - frag_color = min(frag_color * feedback, vec4(luminance_cap)); - -#endif - -#ifdef SIMPLE_COPY - vec4 color = textureLod(source_color, uv_interp, 0.0); - frag_color = color; -#endif - -#ifdef SSAO_MERGE - - vec4 color = textureLod(source_color, uv_interp, 0.0); - float ssao = textureLod(source_ssao, uv_interp, 0.0).r; - - frag_color = vec4(mix(color.rgb, color.rgb * mix(ssao_color.rgb, vec3(1.0), ssao), color.a), 1.0); - -#endif -} diff --git a/drivers/gles3/shaders/exposure.glsl b/drivers/gles3/shaders/exposure.glsl deleted file mode 100644 index 759adcda06..0000000000 --- a/drivers/gles3/shaders/exposure.glsl +++ /dev/null @@ -1,88 +0,0 @@ -/* clang-format off */ -[vertex] - -layout(location = 0) in highp vec4 vertex_attrib; -/* clang-format on */ - -void main() { - - gl_Position = vertex_attrib; -} - -/* clang-format off */ -[fragment] - -uniform highp sampler2D source_exposure; //texunit:0 -/* clang-format on */ - -#ifdef EXPOSURE_BEGIN - -uniform highp ivec2 source_render_size; -uniform highp ivec2 target_size; - -#endif - -#ifdef EXPOSURE_END - -uniform highp sampler2D prev_exposure; //texunit:1 -uniform highp float exposure_adjust; -uniform highp float min_luminance; -uniform highp float max_luminance; - -#endif - -layout(location = 0) out highp float exposure; - -void main() { - -#ifdef EXPOSURE_BEGIN - - ivec2 src_pos = ivec2(gl_FragCoord.xy) * source_render_size / target_size; - -#if 1 - //more precise and expensive, but less jittery - ivec2 next_pos = ivec2(gl_FragCoord.xy + ivec2(1)) * source_render_size / target_size; - next_pos = max(next_pos, src_pos + ivec2(1)); //so it at least reads one pixel - highp vec3 source_color = vec3(0.0); - for (int i = src_pos.x; i < next_pos.x; i++) { - for (int j = src_pos.y; j < next_pos.y; j++) { - source_color += texelFetch(source_exposure, ivec2(i, j), 0).rgb; - } - } - - source_color /= float((next_pos.x - src_pos.x) * (next_pos.y - src_pos.y)); -#else - highp vec3 source_color = texelFetch(source_exposure, src_pos, 0).rgb; - -#endif - - exposure = max(source_color.r, max(source_color.g, source_color.b)); - -#else - - ivec2 coord = ivec2(gl_FragCoord.xy); - exposure = texelFetch(source_exposure, coord * 3 + ivec2(0, 0), 0).r; - exposure += texelFetch(source_exposure, coord * 3 + ivec2(1, 0), 0).r; - exposure += texelFetch(source_exposure, coord * 3 + ivec2(2, 0), 0).r; - exposure += texelFetch(source_exposure, coord * 3 + ivec2(0, 1), 0).r; - exposure += texelFetch(source_exposure, coord * 3 + ivec2(1, 1), 0).r; - exposure += texelFetch(source_exposure, coord * 3 + ivec2(2, 1), 0).r; - exposure += texelFetch(source_exposure, coord * 3 + ivec2(0, 2), 0).r; - exposure += texelFetch(source_exposure, coord * 3 + ivec2(1, 2), 0).r; - exposure += texelFetch(source_exposure, coord * 3 + ivec2(2, 2), 0).r; - exposure *= (1.0 / 9.0); - -#ifdef EXPOSURE_END - -#ifdef EXPOSURE_FORCE_SET - //will stay as is -#else - highp float prev_lum = texelFetch(prev_exposure, ivec2(0, 0), 0).r; //1 pixel previous exposure - exposure = clamp(prev_lum + (exposure - prev_lum) * exposure_adjust, min_luminance, max_luminance); - -#endif //EXPOSURE_FORCE_SET - -#endif //EXPOSURE_END - -#endif //EXPOSURE_BEGIN -} diff --git a/drivers/gles3/shaders/lens_distorted.glsl b/drivers/gles3/shaders/lens_distorted.glsl deleted file mode 100644 index 7b9d0b347f..0000000000 --- a/drivers/gles3/shaders/lens_distorted.glsl +++ /dev/null @@ -1,64 +0,0 @@ -/* clang-format off */ -[vertex] - -layout(location = 0) in highp vec4 vertex_attrib; -/* clang-format on */ - -uniform vec2 offset; -uniform vec2 scale; - -out vec2 uv_interp; - -void main() { - - uv_interp = vertex_attrib.xy * 2.0 - 1.0; - - vec2 v = vertex_attrib.xy * scale + offset; - gl_Position = vec4(v, 0.0, 1.0); -} - -/* clang-format off */ -[fragment] - -uniform sampler2D source; //texunit:0 -/* clang-format on */ - -uniform vec2 eye_center; -uniform float k1; -uniform float k2; -uniform float upscale; -uniform float aspect_ratio; - -in vec2 uv_interp; - -layout(location = 0) out vec4 frag_color; - -void main() { - vec2 coords = uv_interp; - vec2 offset = coords - eye_center; - - // take aspect ratio into account - offset.y /= aspect_ratio; - - // distort - vec2 offset_sq = offset * offset; - float radius_sq = offset_sq.x + offset_sq.y; - float radius_s4 = radius_sq * radius_sq; - float distortion_scale = 1.0 + (k1 * radius_sq) + (k2 * radius_s4); - offset *= distortion_scale; - - // reapply aspect ratio - offset.y *= aspect_ratio; - - // add our eye center back in - coords = offset + eye_center; - coords /= upscale; - - // and check our color - if (coords.x < -1.0 || coords.y < -1.0 || coords.x > 1.0 || coords.y > 1.0) { - frag_color = vec4(0.0, 0.0, 0.0, 1.0); - } else { - coords = (coords + vec2(1.0)) / vec2(2.0); - frag_color = textureLod(source, coords, 0.0); - } -} diff --git a/drivers/gles3/shaders/particles.glsl b/drivers/gles3/shaders/particles.glsl deleted file mode 100644 index 8523c08597..0000000000 --- a/drivers/gles3/shaders/particles.glsl +++ /dev/null @@ -1,267 +0,0 @@ -/* clang-format off */ -[vertex] - -layout(location = 0) in highp vec4 color; -/* clang-format on */ -layout(location = 1) in highp vec4 velocity_active; -layout(location = 2) in highp vec4 custom; -layout(location = 3) in highp vec4 xform_1; -layout(location = 4) in highp vec4 xform_2; -layout(location = 5) in highp vec4 xform_3; - -struct Attractor { - - vec3 pos; - vec3 dir; - float radius; - float eat_radius; - float strength; - float attenuation; -}; - -#define MAX_ATTRACTORS 64 - -uniform bool emitting; -uniform float system_phase; -uniform float prev_system_phase; -uniform int total_particles; -uniform float explosiveness; -uniform float randomness; -uniform float time; -uniform float delta; - -uniform int attractor_count; -uniform Attractor attractors[MAX_ATTRACTORS]; -uniform bool clear; -uniform uint cycle; -uniform float lifetime; -uniform mat4 emission_transform; -uniform uint random_seed; - -out highp vec4 out_color; //tfb: -out highp vec4 out_velocity_active; //tfb: -out highp vec4 out_custom; //tfb: -out highp vec4 out_xform_1; //tfb: -out highp vec4 out_xform_2; //tfb: -out highp vec4 out_xform_3; //tfb: - -#if defined(USE_MATERIAL) - -/* clang-format off */ -layout(std140) uniform UniformData { //ubo:0 - -MATERIAL_UNIFORMS - -}; -/* clang-format on */ - -#endif - -/* clang-format off */ - -VERTEX_SHADER_GLOBALS - -/* clang-format on */ - -uint hash(uint x) { - - x = ((x >> uint(16)) ^ x) * uint(0x45d9f3b); - x = ((x >> uint(16)) ^ x) * uint(0x45d9f3b); - x = (x >> uint(16)) ^ x; - return x; -} - -void main() { - -#ifdef PARTICLES_COPY - - out_color = color; - out_velocity_active = velocity_active; - out_custom = custom; - out_xform_1 = xform_1; - out_xform_2 = xform_2; - out_xform_3 = xform_3; - -#else - - bool apply_forces = true; - bool apply_velocity = true; - float local_delta = delta; - - float mass = 1.0; - - float restart_phase = float(gl_VertexID) / float(total_particles); - - if (randomness > 0.0) { - uint seed = cycle; - if (restart_phase >= system_phase) { - seed -= uint(1); - } - seed *= uint(total_particles); - seed += uint(gl_VertexID); - float random = float(hash(seed) % uint(65536)) / 65536.0; - restart_phase += randomness * random * 1.0 / float(total_particles); - } - - restart_phase *= (1.0 - explosiveness); - bool restart = false; - bool shader_active = velocity_active.a > 0.5; - - if (system_phase > prev_system_phase) { - // restart_phase >= prev_system_phase is used so particles emit in the first frame they are processed - - if (restart_phase >= prev_system_phase && restart_phase < system_phase) { - restart = true; -#ifdef USE_FRACTIONAL_DELTA - local_delta = (system_phase - restart_phase) * lifetime; -#endif - } - - } else if (delta > 0.0) { - if (restart_phase >= prev_system_phase) { - restart = true; -#ifdef USE_FRACTIONAL_DELTA - local_delta = (1.0 - restart_phase + system_phase) * lifetime; -#endif - } else if (restart_phase < system_phase) { - restart = true; -#ifdef USE_FRACTIONAL_DELTA - local_delta = (system_phase - restart_phase) * lifetime; -#endif - } - } - - uint current_cycle = cycle; - - if (system_phase < restart_phase) { - current_cycle -= uint(1); - } - - uint particle_number = current_cycle * uint(total_particles) + uint(gl_VertexID); - int index = int(gl_VertexID); - - if (restart) { - shader_active = emitting; - } - - mat4 xform; - -#if defined(ENABLE_KEEP_DATA) - if (clear) { -#else - if (clear || restart) { -#endif - out_color = vec4(1.0); - out_velocity_active = vec4(0.0); - out_custom = vec4(0.0); - if (!restart) - shader_active = false; - - xform = mat4( - vec4(1.0, 0.0, 0.0, 0.0), - vec4(0.0, 1.0, 0.0, 0.0), - vec4(0.0, 0.0, 1.0, 0.0), - vec4(0.0, 0.0, 0.0, 1.0)); - } else { - out_color = color; - out_velocity_active = velocity_active; - out_custom = custom; - xform = transpose(mat4(xform_1, xform_2, xform_3, vec4(vec3(0.0), 1.0))); - } - - if (shader_active) { - //execute shader - - { - /* clang-format off */ - -VERTEX_SHADER_CODE - - /* clang-format on */ - } - -#if !defined(DISABLE_FORCE) - - if (false) { - - vec3 force = vec3(0.0); - for (int i = 0; i < attractor_count; i++) { - - vec3 rel_vec = xform[3].xyz - attractors[i].pos; - float dist = length(rel_vec); - if (attractors[i].radius < dist) - continue; - if (attractors[i].eat_radius > 0.0 && attractors[i].eat_radius > dist) { - out_velocity_active.a = 0.0; - } - - rel_vec = normalize(rel_vec); - - float attenuation = pow(dist / attractors[i].radius, attractors[i].attenuation); - - if (attractors[i].dir == vec3(0.0)) { - //towards center - force += attractors[i].strength * rel_vec * attenuation * mass; - } else { - force += attractors[i].strength * attractors[i].dir * attenuation * mass; - } - } - - out_velocity_active.xyz += force * local_delta; - } -#endif - -#if !defined(DISABLE_VELOCITY) - - if (true) { - - xform[3].xyz += out_velocity_active.xyz * local_delta; - } -#endif - } else { - xform = mat4(0.0); - } - - xform = transpose(xform); - - out_velocity_active.a = mix(0.0, 1.0, shader_active); - - out_xform_1 = xform[0]; - out_xform_2 = xform[1]; - out_xform_3 = xform[2]; - -#endif //PARTICLES_COPY -} - -/* clang-format off */ -[fragment] - -// any code here is never executed, stuff is filled just so it works - -#if defined(USE_MATERIAL) - -layout(std140) uniform UniformData { - -MATERIAL_UNIFORMS - -}; - -#endif - -FRAGMENT_SHADER_GLOBALS - -void main() { - - { - -LIGHT_SHADER_CODE - - } - - { - -FRAGMENT_SHADER_CODE - - } -} -/* clang-format on */ diff --git a/drivers/gles3/shaders/resolve.glsl b/drivers/gles3/shaders/resolve.glsl deleted file mode 100644 index d64d8308c1..0000000000 --- a/drivers/gles3/shaders/resolve.glsl +++ /dev/null @@ -1,44 +0,0 @@ -/* clang-format off */ -[vertex] - -layout(location = 0) in highp vec4 vertex_attrib; -/* clang-format on */ -layout(location = 4) in vec2 uv_in; - -out vec2 uv_interp; - -void main() { - - uv_interp = uv_in; - gl_Position = vertex_attrib; -} - -/* clang-format off */ -[fragment] - -#if !defined(GLES_OVER_GL) -precision mediump float; -#endif -/* clang-format on */ - -in vec2 uv_interp; -uniform sampler2D source_specular; // texunit:0 -uniform sampler2D source_ssr; // texunit:1 - -uniform vec2 pixel_size; - -in vec2 uv2_interp; - -layout(location = 0) out vec4 frag_color; - -void main() { - - vec4 specular = texture(source_specular, uv_interp); - -#ifdef USE_SSR - vec4 ssr = textureLod(source_ssr, uv_interp, 0.0); - specular.rgb = mix(specular.rgb, ssr.rgb * specular.a, ssr.a); -#endif - - frag_color = vec4(specular.rgb, 1.0); -} diff --git a/drivers/gles3/shaders/scene.glsl b/drivers/gles3/shaders/scene.glsl deleted file mode 100644 index a45ac2eb8a..0000000000 --- a/drivers/gles3/shaders/scene.glsl +++ /dev/null @@ -1,2187 +0,0 @@ -/* clang-format off */ -[vertex] - -#define M_PI 3.14159265359 - -#define SHADER_IS_SRGB false - -/* -from VisualServer: - -ARRAY_VERTEX=0, -ARRAY_NORMAL=1, -ARRAY_TANGENT=2, -ARRAY_COLOR=3, -ARRAY_TEX_UV=4, -ARRAY_TEX_UV2=5, -ARRAY_BONES=6, -ARRAY_WEIGHTS=7, -ARRAY_INDEX=8, -*/ - -// hack to use uv if no uv present so it works with lightmap - -/* INPUT ATTRIBS */ - -layout(location = 0) in highp vec4 vertex_attrib; -/* clang-format on */ -layout(location = 1) in vec3 normal_attrib; -#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) || defined(LIGHT_USE_ANISOTROPY) -layout(location = 2) in vec4 tangent_attrib; -#endif - -#if defined(ENABLE_COLOR_INTERP) -layout(location = 3) in vec4 color_attrib; -#endif - -#if defined(ENABLE_UV_INTERP) -layout(location = 4) in vec2 uv_attrib; -#endif - -#if defined(ENABLE_UV2_INTERP) || defined(USE_LIGHTMAP) -layout(location = 5) in vec2 uv2_attrib; -#endif - -#ifdef USE_SKELETON -layout(location = 6) in uvec4 bone_indices; // attrib:6 -layout(location = 7) in highp vec4 bone_weights; // attrib:7 -#endif - -#ifdef USE_INSTANCING - -layout(location = 8) in highp vec4 instance_xform0; -layout(location = 9) in highp vec4 instance_xform1; -layout(location = 10) in highp vec4 instance_xform2; -layout(location = 11) in lowp vec4 instance_color; - -#if defined(ENABLE_INSTANCE_CUSTOM) -layout(location = 12) in highp vec4 instance_custom_data; -#endif - -#endif - -layout(std140) uniform SceneData { // ubo:0 - - highp mat4 projection_matrix; - highp mat4 inv_projection_matrix; - highp mat4 camera_inverse_matrix; - highp mat4 camera_matrix; - - mediump vec4 ambient_light_color; - mediump vec4 bg_color; - - mediump vec4 fog_color_enabled; - mediump vec4 fog_sun_color_amount; - - mediump float ambient_energy; - mediump float bg_energy; - - mediump float z_offset; - mediump float z_slope_scale; - highp float shadow_dual_paraboloid_render_zfar; - highp float shadow_dual_paraboloid_render_side; - - highp vec2 viewport_size; - highp vec2 screen_pixel_size; - highp vec2 shadow_atlas_pixel_size; - highp vec2 directional_shadow_pixel_size; - - highp float time; - highp float z_far; - mediump float reflection_multiplier; - mediump float subsurface_scatter_width; - mediump float ambient_occlusion_affect_light; - mediump float ambient_occlusion_affect_ao_channel; - mediump float opaque_prepass_threshold; - - bool fog_depth_enabled; - highp float fog_depth_begin; - highp float fog_depth_end; - mediump float fog_density; - highp float fog_depth_curve; - bool fog_transmit_enabled; - highp float fog_transmit_curve; - bool fog_height_enabled; - highp float fog_height_min; - highp float fog_height_max; - highp float fog_height_curve; -}; - -uniform highp mat4 world_transform; - -#ifdef USE_LIGHT_DIRECTIONAL - -layout(std140) uniform DirectionalLightData { //ubo:3 - - highp vec4 light_pos_inv_radius; - mediump vec4 light_direction_attenuation; - mediump vec4 light_color_energy; - mediump vec4 light_params; // cone attenuation, angle, specular, shadow enabled, - mediump vec4 light_clamp; - mediump vec4 shadow_color_contact; - highp mat4 shadow_matrix1; - highp mat4 shadow_matrix2; - highp mat4 shadow_matrix3; - highp mat4 shadow_matrix4; - mediump vec4 shadow_split_offsets; -}; - -#endif - -#ifdef USE_VERTEX_LIGHTING -//omni and spot - -struct LightData { - - highp vec4 light_pos_inv_radius; - mediump vec4 light_direction_attenuation; - mediump vec4 light_color_energy; - mediump vec4 light_params; // cone attenuation, angle, specular, shadow enabled, - mediump vec4 light_clamp; - mediump vec4 shadow_color_contact; - highp mat4 shadow_matrix; -}; - -layout(std140) uniform OmniLightData { //ubo:4 - - LightData omni_lights[MAX_LIGHT_DATA_STRUCTS]; -}; - -layout(std140) uniform SpotLightData { //ubo:5 - - LightData spot_lights[MAX_LIGHT_DATA_STRUCTS]; -}; - -#ifdef USE_FORWARD_LIGHTING - -uniform int omni_light_indices[MAX_FORWARD_LIGHTS]; -uniform int omni_light_count; - -uniform int spot_light_indices[MAX_FORWARD_LIGHTS]; -uniform int spot_light_count; - -#endif - -out vec4 diffuse_light_interp; -out vec4 specular_light_interp; - -void light_compute(vec3 N, vec3 L, vec3 V, vec3 light_color, float roughness, inout vec3 diffuse, inout vec3 specular) { - - float NdotL = dot(N, L); - float cNdotL = max(NdotL, 0.0); // clamped NdotL - float NdotV = dot(N, V); - float cNdotV = max(NdotV, 0.0); - -#if defined(DIFFUSE_OREN_NAYAR) - vec3 diffuse_brdf_NL; -#else - float diffuse_brdf_NL; // BRDF times N.L for calculating diffuse radiance -#endif - -#if defined(DIFFUSE_LAMBERT_WRAP) - // energy conserving lambert wrap shader - diffuse_brdf_NL = max(0.0, (NdotL + roughness) / ((1.0 + roughness) * (1.0 + roughness))); - -#elif defined(DIFFUSE_OREN_NAYAR) - - { - // see http://mimosa-pudica.net/improved-oren-nayar.html - float LdotV = dot(L, V); - - float s = LdotV - NdotL * NdotV; - float t = mix(1.0, max(NdotL, NdotV), step(0.0, s)); - - float sigma2 = roughness * roughness; // TODO: this needs checking - vec3 A = 1.0 + sigma2 * (-0.5 / (sigma2 + 0.33) + 0.17 * diffuse_color / (sigma2 + 0.13)); - float B = 0.45 * sigma2 / (sigma2 + 0.09); - - diffuse_brdf_NL = cNdotL * (A + vec3(B) * s / t) * (1.0 / M_PI); - } -#else - // lambert by default for everything else - diffuse_brdf_NL = cNdotL * (1.0 / M_PI); -#endif - - diffuse += light_color * diffuse_brdf_NL; - - if (roughness > 0.0) { - - // D - float specular_brdf_NL = 0.0; - -#if !defined(SPECULAR_DISABLED) - //normalized blinn always unless disabled - vec3 H = normalize(V + L); - float cNdotH = max(dot(N, H), 0.0); - float shininess = exp2(15.0 * (1.0 - roughness) + 1.0) * 0.25; - float blinn = pow(cNdotH, shininess) * cNdotL; - blinn *= (shininess + 8.0) * (1.0 / (8.0 * M_PI)); - specular_brdf_NL = blinn; -#endif - - specular += specular_brdf_NL * light_color * (1.0 / M_PI); - } -} - -void light_process_omni(int idx, vec3 vertex, vec3 eye_vec, vec3 normal, float roughness, inout vec3 diffuse, inout vec3 specular) { - - vec3 light_rel_vec = omni_lights[idx].light_pos_inv_radius.xyz - vertex; - float light_length = length(light_rel_vec); - float normalized_distance = light_length * omni_lights[idx].light_pos_inv_radius.w; - vec3 light_attenuation = vec3(pow(max(1.0 - normalized_distance, 0.0), omni_lights[idx].light_direction_attenuation.w)); - - light_compute(normal, normalize(light_rel_vec), eye_vec, omni_lights[idx].light_color_energy.rgb * light_attenuation, roughness, diffuse, specular); -} - -void light_process_spot(int idx, vec3 vertex, vec3 eye_vec, vec3 normal, float roughness, inout vec3 diffuse, inout vec3 specular) { - - vec3 light_rel_vec = spot_lights[idx].light_pos_inv_radius.xyz - vertex; - float light_length = length(light_rel_vec); - float normalized_distance = light_length * spot_lights[idx].light_pos_inv_radius.w; - vec3 light_attenuation = vec3(pow(max(1.0 - normalized_distance, 0.001), spot_lights[idx].light_direction_attenuation.w)); - vec3 spot_dir = spot_lights[idx].light_direction_attenuation.xyz; - float spot_cutoff = spot_lights[idx].light_params.y; - float scos = max(dot(-normalize(light_rel_vec), spot_dir), spot_cutoff); - float spot_rim = (1.0 - scos) / (1.0 - spot_cutoff); - light_attenuation *= 1.0 - pow(max(spot_rim, 0.001), spot_lights[idx].light_params.x); - - light_compute(normal, normalize(light_rel_vec), eye_vec, spot_lights[idx].light_color_energy.rgb * light_attenuation, roughness, diffuse, specular); -} - -#endif - -/* Varyings */ - -out highp vec3 vertex_interp; -out vec3 normal_interp; - -#if defined(ENABLE_COLOR_INTERP) -out vec4 color_interp; -#endif - -#if defined(ENABLE_UV_INTERP) -out vec2 uv_interp; -#endif - -#if defined(ENABLE_UV2_INTERP) || defined(USE_LIGHTMAP) -out vec2 uv2_interp; -#endif - -#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) || defined(LIGHT_USE_ANISOTROPY) -out vec3 tangent_interp; -out vec3 binormal_interp; -#endif - -#if defined(USE_MATERIAL) - -/* clang-format off */ -layout(std140) uniform UniformData { // ubo:1 - -MATERIAL_UNIFORMS - -}; -/* clang-format on */ - -#endif - -/* clang-format off */ - -VERTEX_SHADER_GLOBALS - -/* clang-format on */ - -#ifdef RENDER_DEPTH_DUAL_PARABOLOID - -out highp float dp_clip; - -#endif - -#define SKELETON_TEXTURE_WIDTH 256 - -#ifdef USE_SKELETON -uniform highp sampler2D skeleton_texture; // texunit:-1 -#endif - -out highp vec4 position_interp; - -// FIXME: This triggers a Mesa bug that breaks rendering, so disabled for now. -// See GH-13450 and https://bugs.freedesktop.org/show_bug.cgi?id=100316 -//invariant gl_Position; - -void main() { - - highp vec4 vertex = vertex_attrib; // vec4(vertex_attrib.xyz * data_attrib.x,1.0); - - highp mat4 world_matrix = world_transform; - -#ifdef USE_INSTANCING - - { - highp mat4 m = mat4(instance_xform0, instance_xform1, instance_xform2, vec4(0.0, 0.0, 0.0, 1.0)); - world_matrix = world_matrix * transpose(m); - } -#endif - - vec3 normal = normal_attrib; - -#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) || defined(LIGHT_USE_ANISOTROPY) - vec3 tangent = tangent_attrib.xyz; - float binormalf = tangent_attrib.a; -#endif - -#if defined(ENABLE_COLOR_INTERP) - color_interp = color_attrib; -#if defined(USE_INSTANCING) - color_interp *= instance_color; -#endif - -#endif - -#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) || defined(LIGHT_USE_ANISOTROPY) - - vec3 binormal = normalize(cross(normal, tangent) * binormalf); -#endif - -#if defined(ENABLE_UV_INTERP) - uv_interp = uv_attrib; -#endif - -#if defined(ENABLE_UV2_INTERP) || defined(USE_LIGHTMAP) - uv2_interp = uv2_attrib; -#endif - -#ifdef OVERRIDE_POSITION - highp vec4 position; -#endif - -#if defined(USE_INSTANCING) && defined(ENABLE_INSTANCE_CUSTOM) - vec4 instance_custom = instance_custom_data; -#else - vec4 instance_custom = vec4(0.0); -#endif - - highp mat4 local_projection = projection_matrix; - -//using world coordinates -#if !defined(SKIP_TRANSFORM_USED) && defined(VERTEX_WORLD_COORDS_USED) - - vertex = world_matrix * vertex; - -#if defined(ENSURE_CORRECT_NORMALS) - mat3 normal_matrix = mat3(transpose(inverse(world_matrix))); - normal = normal_matrix * normal; -#else - normal = normalize((world_matrix * vec4(normal, 0.0)).xyz); -#endif - -#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) || defined(LIGHT_USE_ANISOTROPY) - - tangent = normalize((world_matrix * vec4(tangent, 0.0)).xyz); - binormal = normalize((world_matrix * vec4(binormal, 0.0)).xyz); -#endif -#endif - - float roughness = 1.0; - -//defines that make writing custom shaders easier -#define projection_matrix local_projection -#define world_transform world_matrix - -#ifdef USE_SKELETON - { - //skeleton transform - ivec4 bone_indicesi = ivec4(bone_indices); // cast to signed int - - ivec2 tex_ofs = ivec2(bone_indicesi.x % 256, (bone_indicesi.x / 256) * 3); - highp mat4 m; - m = mat4( - texelFetch(skeleton_texture, tex_ofs, 0), - texelFetch(skeleton_texture, tex_ofs + ivec2(0, 1), 0), - texelFetch(skeleton_texture, tex_ofs + ivec2(0, 2), 0), - vec4(0.0, 0.0, 0.0, 1.0)) * - bone_weights.x; - - tex_ofs = ivec2(bone_indicesi.y % 256, (bone_indicesi.y / 256) * 3); - - m += mat4( - texelFetch(skeleton_texture, tex_ofs, 0), - texelFetch(skeleton_texture, tex_ofs + ivec2(0, 1), 0), - texelFetch(skeleton_texture, tex_ofs + ivec2(0, 2), 0), - vec4(0.0, 0.0, 0.0, 1.0)) * - bone_weights.y; - - tex_ofs = ivec2(bone_indicesi.z % 256, (bone_indicesi.z / 256) * 3); - - m += mat4( - texelFetch(skeleton_texture, tex_ofs, 0), - texelFetch(skeleton_texture, tex_ofs + ivec2(0, 1), 0), - texelFetch(skeleton_texture, tex_ofs + ivec2(0, 2), 0), - vec4(0.0, 0.0, 0.0, 1.0)) * - bone_weights.z; - - tex_ofs = ivec2(bone_indicesi.w % 256, (bone_indicesi.w / 256) * 3); - - m += mat4( - texelFetch(skeleton_texture, tex_ofs, 0), - texelFetch(skeleton_texture, tex_ofs + ivec2(0, 1), 0), - texelFetch(skeleton_texture, tex_ofs + ivec2(0, 2), 0), - vec4(0.0, 0.0, 0.0, 1.0)) * - bone_weights.w; - - world_matrix = world_matrix * transpose(m); - } -#endif - - float point_size = 1.0; - - highp mat4 modelview = camera_inverse_matrix * world_matrix; - { - /* clang-format off */ - -VERTEX_SHADER_CODE - - /* clang-format on */ - } - - gl_PointSize = point_size; - -// using local coordinates (default) -#if !defined(SKIP_TRANSFORM_USED) && !defined(VERTEX_WORLD_COORDS_USED) - - vertex = modelview * vertex; - -#if defined(ENSURE_CORRECT_NORMALS) - mat3 normal_matrix = mat3(transpose(inverse(modelview))); - normal = normal_matrix * normal; -#else - normal = normalize((modelview * vec4(normal, 0.0)).xyz); -#endif - -#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) || defined(LIGHT_USE_ANISOTROPY) - - tangent = normalize((modelview * vec4(tangent, 0.0)).xyz); - binormal = normalize((modelview * vec4(binormal, 0.0)).xyz); -#endif -#endif - -//using world coordinates -#if !defined(SKIP_TRANSFORM_USED) && defined(VERTEX_WORLD_COORDS_USED) - - vertex = camera_inverse_matrix * vertex; - normal = normalize((camera_inverse_matrix * vec4(normal, 0.0)).xyz); - -#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) || defined(LIGHT_USE_ANISOTROPY) - - tangent = normalize((camera_inverse_matrix * vec4(tangent, 0.0)).xyz); - binormal = normalize((camera_inverse_matrix * vec4(binormal, 0.0)).xyz); -#endif -#endif - - vertex_interp = vertex.xyz; - normal_interp = normal; - -#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) || defined(LIGHT_USE_ANISOTROPY) - tangent_interp = tangent; - binormal_interp = binormal; -#endif - -#ifdef RENDER_DEPTH - -#ifdef RENDER_DEPTH_DUAL_PARABOLOID - - vertex_interp.z *= shadow_dual_paraboloid_render_side; - normal_interp.z *= shadow_dual_paraboloid_render_side; - - dp_clip = vertex_interp.z; //this attempts to avoid noise caused by objects sent to the other parabolloid side due to bias - - //for dual paraboloid shadow mapping, this is the fastest but least correct way, as it curves straight edges - - highp vec3 vtx = vertex_interp + normalize(vertex_interp) * z_offset; - highp float distance = length(vtx); - vtx = normalize(vtx); - vtx.xy /= 1.0 - vtx.z; - vtx.z = (distance / shadow_dual_paraboloid_render_zfar); - vtx.z = vtx.z * 2.0 - 1.0; - - vertex_interp = vtx; - -#else - - float z_ofs = z_offset; - z_ofs += (1.0 - abs(normal_interp.z)) * z_slope_scale; - vertex_interp.z -= z_ofs; - -#endif //RENDER_DEPTH_DUAL_PARABOLOID - -#endif //RENDER_DEPTH - -#ifdef OVERRIDE_POSITION - gl_Position = position; -#else - gl_Position = projection_matrix * vec4(vertex_interp, 1.0); -#endif - - position_interp = gl_Position; - -#ifdef USE_VERTEX_LIGHTING - - diffuse_light_interp = vec4(0.0); - specular_light_interp = vec4(0.0); - -#ifdef USE_FORWARD_LIGHTING - - for (int i = 0; i < omni_light_count; i++) { - light_process_omni(omni_light_indices[i], vertex_interp, -normalize(vertex_interp), normal_interp, roughness, diffuse_light_interp.rgb, specular_light_interp.rgb); - } - - for (int i = 0; i < spot_light_count; i++) { - light_process_spot(spot_light_indices[i], vertex_interp, -normalize(vertex_interp), normal_interp, roughness, diffuse_light_interp.rgb, specular_light_interp.rgb); - } -#endif - -#ifdef USE_LIGHT_DIRECTIONAL - - vec3 directional_diffuse = vec3(0.0); - vec3 directional_specular = vec3(0.0); - light_compute(normal_interp, -light_direction_attenuation.xyz, -normalize(vertex_interp), light_color_energy.rgb, roughness, directional_diffuse, directional_specular); - - float diff_avg = dot(diffuse_light_interp.rgb, vec3(0.33333)); - float diff_dir_avg = dot(directional_diffuse, vec3(0.33333)); - if (diff_avg > 0.0) { - diffuse_light_interp.a = diff_dir_avg / (diff_avg + diff_dir_avg); - } else { - diffuse_light_interp.a = 1.0; - } - - diffuse_light_interp.rgb += directional_diffuse; - - float spec_avg = dot(specular_light_interp.rgb, vec3(0.33333)); - float spec_dir_avg = dot(directional_specular, vec3(0.33333)); - if (spec_avg > 0.0) { - specular_light_interp.a = spec_dir_avg / (spec_avg + spec_dir_avg); - } else { - specular_light_interp.a = 1.0; - } - - specular_light_interp.rgb += directional_specular; - -#endif //USE_LIGHT_DIRECTIONAL - -#endif // USE_VERTEX_LIGHTING -} - -/* clang-format off */ -[fragment] - - -/* texture unit usage, N is max_texture_unity-N - -1-skeleton -2-radiance -3-reflection_atlas -4-directional_shadow -5-shadow_atlas -6-decal_atlas -7-screen -8-depth -9-probe1 -10-probe2 - -*/ - -uniform highp mat4 world_transform; -/* clang-format on */ - -#define M_PI 3.14159265359 -#define SHADER_IS_SRGB false - -/* Varyings */ - -#if defined(ENABLE_COLOR_INTERP) -in vec4 color_interp; -#endif - -#if defined(ENABLE_UV_INTERP) -in vec2 uv_interp; -#endif - -#if defined(ENABLE_UV2_INTERP) || defined(USE_LIGHTMAP) -in vec2 uv2_interp; -#endif - -#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) || defined(LIGHT_USE_ANISOTROPY) -in vec3 tangent_interp; -in vec3 binormal_interp; -#endif - -in highp vec3 vertex_interp; -in vec3 normal_interp; - -/* PBR CHANNELS */ - -#ifdef USE_RADIANCE_MAP - -layout(std140) uniform Radiance { // ubo:2 - - mat4 radiance_inverse_xform; - float radiance_ambient_contribution; -}; - -#define RADIANCE_MAX_LOD 5.0 - -uniform sampler2D irradiance_map; // texunit:-6 - -#ifdef USE_RADIANCE_MAP_ARRAY - -uniform sampler2DArray radiance_map; // texunit:-2 - -vec3 textureDualParaboloid(sampler2DArray p_tex, vec3 p_vec, float p_roughness) { - - vec3 norm = normalize(p_vec); - norm.xy /= 1.0 + abs(norm.z); - norm.xy = norm.xy * vec2(0.5, 0.25) + vec2(0.5, 0.25); - - // we need to lie the derivatives (normg) and assume that DP side is always the same - // to get proper texture filtering - vec2 normg = norm.xy; - if (norm.z > 0.0) { - norm.y = 0.5 - norm.y + 0.5; - } - - // thanks to OpenGL spec using floor(layer + 0.5) for texture arrays, - // it's easy to have precision errors using fract() to interpolate layers - // as such, using fixed point to ensure it works. - - float index = p_roughness * RADIANCE_MAX_LOD; - int indexi = int(index * 256.0); - vec3 base = textureGrad(p_tex, vec3(norm.xy, float(indexi / 256)), dFdx(normg), dFdy(normg)).xyz; - vec3 next = textureGrad(p_tex, vec3(norm.xy, float(indexi / 256 + 1)), dFdx(normg), dFdy(normg)).xyz; - return mix(base, next, float(indexi % 256) / 256.0); -} - -#else - -uniform sampler2D radiance_map; // texunit:-2 - -vec3 textureDualParaboloid(sampler2D p_tex, vec3 p_vec, float p_roughness) { - - vec3 norm = normalize(p_vec); - norm.xy /= 1.0 + abs(norm.z); - norm.xy = norm.xy * vec2(0.5, 0.25) + vec2(0.5, 0.25); - if (norm.z > 0.0) { - norm.y = 0.5 - norm.y + 0.5; - } - return textureLod(p_tex, norm.xy, p_roughness * RADIANCE_MAX_LOD).xyz; -} - -#endif - -#endif - -/* Material Uniforms */ - -#if defined(USE_MATERIAL) - -/* clang-format off */ -layout(std140) uniform UniformData { - -MATERIAL_UNIFORMS - -}; -/* clang-format on */ - -#endif - -/* clang-format off */ - -FRAGMENT_SHADER_GLOBALS - -/* clang-format on */ - -layout(std140) uniform SceneData { - - highp mat4 projection_matrix; - highp mat4 inv_projection_matrix; - highp mat4 camera_inverse_matrix; - highp mat4 camera_matrix; - - mediump vec4 ambient_light_color; - mediump vec4 bg_color; - - mediump vec4 fog_color_enabled; - mediump vec4 fog_sun_color_amount; - - mediump float ambient_energy; - mediump float bg_energy; - - mediump float z_offset; - mediump float z_slope_scale; - highp float shadow_dual_paraboloid_render_zfar; - highp float shadow_dual_paraboloid_render_side; - - highp vec2 viewport_size; - highp vec2 screen_pixel_size; - highp vec2 shadow_atlas_pixel_size; - highp vec2 directional_shadow_pixel_size; - - highp float time; - highp float z_far; - mediump float reflection_multiplier; - mediump float subsurface_scatter_width; - mediump float ambient_occlusion_affect_light; - mediump float ambient_occlusion_affect_ao_channel; - mediump float opaque_prepass_threshold; - - bool fog_depth_enabled; - highp float fog_depth_begin; - highp float fog_depth_end; - mediump float fog_density; - highp float fog_depth_curve; - bool fog_transmit_enabled; - highp float fog_transmit_curve; - bool fog_height_enabled; - highp float fog_height_min; - highp float fog_height_max; - highp float fog_height_curve; -}; - - //directional light data - -#ifdef USE_LIGHT_DIRECTIONAL - -layout(std140) uniform DirectionalLightData { - - highp vec4 light_pos_inv_radius; - mediump vec4 light_direction_attenuation; - mediump vec4 light_color_energy; - mediump vec4 light_params; // cone attenuation, angle, specular, shadow enabled, - mediump vec4 light_clamp; - mediump vec4 shadow_color_contact; - highp mat4 shadow_matrix1; - highp mat4 shadow_matrix2; - highp mat4 shadow_matrix3; - highp mat4 shadow_matrix4; - mediump vec4 shadow_split_offsets; -}; - -uniform highp sampler2DShadow directional_shadow; // texunit:-4 - -#endif - -#ifdef USE_VERTEX_LIGHTING -in vec4 diffuse_light_interp; -in vec4 specular_light_interp; -#endif -// omni and spot - -struct LightData { - - highp vec4 light_pos_inv_radius; - mediump vec4 light_direction_attenuation; - mediump vec4 light_color_energy; - mediump vec4 light_params; // cone attenuation, angle, specular, shadow enabled, - mediump vec4 light_clamp; - mediump vec4 shadow_color_contact; - highp mat4 shadow_matrix; -}; - -layout(std140) uniform OmniLightData { // ubo:4 - - LightData omni_lights[MAX_LIGHT_DATA_STRUCTS]; -}; - -layout(std140) uniform SpotLightData { // ubo:5 - - LightData spot_lights[MAX_LIGHT_DATA_STRUCTS]; -}; - -uniform highp sampler2DShadow shadow_atlas; // texunit:-5 - -struct ReflectionData { - - mediump vec4 box_extents; - mediump vec4 box_offset; - mediump vec4 params; // intensity, 0, interior , boxproject - mediump vec4 ambient; // ambient color, energy - mediump vec4 atlas_clamp; - highp mat4 local_matrix; // up to here for spot and omni, rest is for directional - // notes: for ambientblend, use distance to edge to blend between already existing global environment -}; - -layout(std140) uniform ReflectionProbeData { //ubo:6 - - ReflectionData reflections[MAX_REFLECTION_DATA_STRUCTS]; -}; -uniform mediump sampler2D reflection_atlas; // texunit:-3 - -#ifdef USE_FORWARD_LIGHTING - -uniform int omni_light_indices[MAX_FORWARD_LIGHTS]; -uniform int omni_light_count; - -uniform int spot_light_indices[MAX_FORWARD_LIGHTS]; -uniform int spot_light_count; - -uniform int reflection_indices[MAX_FORWARD_LIGHTS]; -uniform int reflection_count; - -#endif - -#if defined(SCREEN_TEXTURE_USED) - -uniform highp sampler2D screen_texture; // texunit:-7 - -#endif - -#ifdef USE_MULTIPLE_RENDER_TARGETS - -layout(location = 0) out vec4 diffuse_buffer; -layout(location = 1) out vec4 specular_buffer; -layout(location = 2) out vec4 normal_mr_buffer; -#if defined(ENABLE_SSS) -layout(location = 3) out float sss_buffer; -#endif - -#else - -layout(location = 0) out vec4 frag_color; - -#endif - -in highp vec4 position_interp; -uniform highp sampler2D depth_buffer; // texunit:-8 - -#ifdef USE_CONTACT_SHADOWS - -float contact_shadow_compute(vec3 pos, vec3 dir, float max_distance) { - - if (abs(dir.z) > 0.99) - return 1.0; - - vec3 endpoint = pos + dir * max_distance; - vec4 source = position_interp; - vec4 dest = projection_matrix * vec4(endpoint, 1.0); - - vec2 from_screen = (source.xy / source.w) * 0.5 + 0.5; - vec2 to_screen = (dest.xy / dest.w) * 0.5 + 0.5; - - vec2 screen_rel = to_screen - from_screen; - - if (length(screen_rel) < 0.00001) - return 1.0; // too small, don't do anything - - /* - float pixel_size; // approximate pixel size - - if (screen_rel.x > screen_rel.y) { - - pixel_size = abs((pos.x - endpoint.x) / (screen_rel.x / screen_pixel_size.x)); - } else { - pixel_size = abs((pos.y - endpoint.y) / (screen_rel.y / screen_pixel_size.y)); - } - */ - vec4 bias = projection_matrix * vec4(pos + vec3(0.0, 0.0, max_distance * 0.5), 1.0); - - vec2 pixel_incr = normalize(screen_rel) * screen_pixel_size; - - float steps = length(screen_rel) / length(pixel_incr); - steps = min(2000.0, steps); // put a limit to avoid freezing in some strange situation - //steps = 10.0; - - vec4 incr = (dest - source) / steps; - float ratio = 0.0; - float ratio_incr = 1.0 / steps; - - while (steps > 0.0) { - source += incr * 2.0; - bias += incr * 2.0; - - vec3 uv_depth = (source.xyz / source.w) * 0.5 + 0.5; - if (uv_depth.x > 0.0 && uv_depth.x < 1.0 && uv_depth.y > 0.0 && uv_depth.y < 1.0) { - float depth = texture(depth_buffer, uv_depth.xy).r; - - if (depth < uv_depth.z) { - if (depth > (bias.z / bias.w) * 0.5 + 0.5) { - return min(pow(ratio, 4.0), 1.0); - } else { - return 1.0; - } - } - - ratio += ratio_incr; - steps -= 1.0; - } else { - return 1.0; - } - } - - return 1.0; -} - -#endif - -// This returns the G_GGX function divided by 2 cos_theta_m, where in practice cos_theta_m is either N.L or N.V. -// We're dividing this factor off because the overall term we'll end up looks like -// (see, for example, the first unnumbered equation in B. Burley, "Physically Based Shading at Disney", SIGGRAPH 2012): -// -// F(L.V) D(N.H) G(N.L) G(N.V) / (4 N.L N.V) -// -// We're basically regouping this as -// -// F(L.V) D(N.H) [G(N.L)/(2 N.L)] [G(N.V) / (2 N.V)] -// -// and thus, this function implements the [G(N.m)/(2 N.m)] part with m = L or V. -// -// The contents of the D and G (G1) functions (GGX) are taken from -// E. Heitz, "Understanding the Masking-Shadowing Function in Microfacet-Based BRDFs", J. Comp. Graph. Tech. 3 (2) (2014). -// Eqns 71-72 and 85-86 (see also Eqns 43 and 80). - -float G_GGX_2cos(float cos_theta_m, float alpha) { - // Schlick's approximation - // C. Schlick, "An Inexpensive BRDF Model for Physically-based Rendering", Computer Graphics Forum. 13 (3): 233 (1994) - // Eq. (19), although see Heitz (2014) the about the problems with his derivation. - // It nevertheless approximates GGX well with k = alpha/2. - float k = 0.5 * alpha; - return 0.5 / (cos_theta_m * (1.0 - k) + k); - - // float cos2 = cos_theta_m * cos_theta_m; - // float sin2 = (1.0 - cos2); - // return 1.0 / (cos_theta_m + sqrt(cos2 + alpha * alpha * sin2)); -} - -float D_GGX(float cos_theta_m, float alpha) { - float alpha2 = alpha * alpha; - float d = 1.0 + (alpha2 - 1.0) * cos_theta_m * cos_theta_m; - return alpha2 / (M_PI * d * d); -} - -float G_GGX_anisotropic_2cos(float cos_theta_m, float alpha_x, float alpha_y, float cos_phi, float sin_phi) { - float cos2 = cos_theta_m * cos_theta_m; - float sin2 = (1.0 - cos2); - float s_x = alpha_x * cos_phi; - float s_y = alpha_y * sin_phi; - return 1.0 / max(cos_theta_m + sqrt(cos2 + (s_x * s_x + s_y * s_y) * sin2), 0.001); -} - -float D_GGX_anisotropic(float cos_theta_m, float alpha_x, float alpha_y, float cos_phi, float sin_phi) { - float cos2 = cos_theta_m * cos_theta_m; - float sin2 = (1.0 - cos2); - float r_x = cos_phi / alpha_x; - float r_y = sin_phi / alpha_y; - float d = cos2 + sin2 * (r_x * r_x + r_y * r_y); - return 1.0 / max(M_PI * alpha_x * alpha_y * d * d, 0.001); -} - -float SchlickFresnel(float u) { - float m = 1.0 - u; - float m2 = m * m; - return m2 * m2 * m; // pow(m,5) -} - -float GTR1(float NdotH, float a) { - if (a >= 1.0) return 1.0 / M_PI; - float a2 = a * a; - float t = 1.0 + (a2 - 1.0) * NdotH * NdotH; - return (a2 - 1.0) / (M_PI * log(a2) * t); -} - -vec3 F0(float metallic, float specular, vec3 albedo) { - float dielectric = 0.16 * specular * specular; - // use albedo * metallic as colored specular reflectance at 0 angle for metallic materials; - // see https://google.github.io/filament/Filament.md.html - return mix(vec3(dielectric), albedo, vec3(metallic)); -} - -void light_compute(vec3 N, vec3 L, vec3 V, vec3 B, vec3 T, vec3 light_color, vec3 attenuation, vec3 diffuse_color, vec3 transmission, float specular_blob_intensity, float roughness, float metallic, float specular, float rim, float rim_tint, float clearcoat, float clearcoat_gloss, float anisotropy, inout vec3 diffuse_light, inout vec3 specular_light, inout float alpha) { - -#if defined(USE_LIGHT_SHADER_CODE) - // light is written by the light shader - - vec3 normal = N; - vec3 albedo = diffuse_color; - vec3 light = L; - vec3 view = V; - - /* clang-format off */ - -LIGHT_SHADER_CODE - - /* clang-format on */ - -#else - float NdotL = dot(N, L); - float cNdotL = max(NdotL, 0.0); // clamped NdotL - float NdotV = dot(N, V); - float cNdotV = max(NdotV, 0.0); - -#if defined(DIFFUSE_BURLEY) || defined(SPECULAR_BLINN) || defined(SPECULAR_SCHLICK_GGX) || defined(LIGHT_USE_CLEARCOAT) - vec3 H = normalize(V + L); -#endif - -#if defined(SPECULAR_BLINN) || defined(SPECULAR_SCHLICK_GGX) || defined(LIGHT_USE_CLEARCOAT) - float cNdotH = max(dot(N, H), 0.0); -#endif - -#if defined(DIFFUSE_BURLEY) || defined(SPECULAR_SCHLICK_GGX) || defined(LIGHT_USE_CLEARCOAT) - float cLdotH = max(dot(L, H), 0.0); -#endif - - if (metallic < 1.0) { -#if defined(DIFFUSE_OREN_NAYAR) - vec3 diffuse_brdf_NL; -#else - float diffuse_brdf_NL; // BRDF times N.L for calculating diffuse radiance -#endif - -#if defined(DIFFUSE_LAMBERT_WRAP) - // energy conserving lambert wrap shader - diffuse_brdf_NL = max(0.0, (NdotL + roughness) / ((1.0 + roughness) * (1.0 + roughness))); - -#elif defined(DIFFUSE_OREN_NAYAR) - - { - // see http://mimosa-pudica.net/improved-oren-nayar.html - float LdotV = dot(L, V); - - float s = LdotV - NdotL * NdotV; - float t = mix(1.0, max(NdotL, NdotV), step(0.0, s)); - - float sigma2 = roughness * roughness; // TODO: this needs checking - vec3 A = 1.0 + sigma2 * (-0.5 / (sigma2 + 0.33) + 0.17 * diffuse_color / (sigma2 + 0.13)); - float B = 0.45 * sigma2 / (sigma2 + 0.09); - - diffuse_brdf_NL = cNdotL * (A + vec3(B) * s / t) * (1.0 / M_PI); - } - -#elif defined(DIFFUSE_TOON) - - diffuse_brdf_NL = smoothstep(-roughness, max(roughness, 0.01), NdotL); - -#elif defined(DIFFUSE_BURLEY) - - { - float FD90_minus_1 = 2.0 * cLdotH * cLdotH * roughness - 0.5; - float FdV = 1.0 + FD90_minus_1 * SchlickFresnel(cNdotV); - float FdL = 1.0 + FD90_minus_1 * SchlickFresnel(cNdotL); - diffuse_brdf_NL = (1.0 / M_PI) * FdV * FdL * cNdotL; - /* - float energyBias = mix(roughness, 0.0, 0.5); - float energyFactor = mix(roughness, 1.0, 1.0 / 1.51); - float fd90 = energyBias + 2.0 * VoH * VoH * roughness; - float f0 = 1.0; - float lightScatter = f0 + (fd90 - f0) * pow(1.0 - cNdotL, 5.0); - float viewScatter = f0 + (fd90 - f0) * pow(1.0 - cNdotV, 5.0); - - diffuse_brdf_NL = lightScatter * viewScatter * energyFactor; - */ - } -#else - // lambert - diffuse_brdf_NL = cNdotL * (1.0 / M_PI); -#endif - - diffuse_light += light_color * diffuse_color * diffuse_brdf_NL * attenuation; - -#if defined(TRANSMISSION_USED) - diffuse_light += light_color * diffuse_color * (vec3(1.0 / M_PI) - diffuse_brdf_NL) * transmission * attenuation; -#endif - -#if defined(LIGHT_USE_RIM) - float rim_light = pow(max(0.0, 1.0 - cNdotV), max(0.0, (1.0 - roughness) * 16.0)); - diffuse_light += rim_light * rim * mix(vec3(1.0), diffuse_color, rim_tint) * light_color; -#endif - } - - if (roughness > 0.0) { // FIXME: roughness == 0 should not disable specular light entirely - - // D - -#if defined(SPECULAR_BLINN) - - //normalized blinn - float shininess = exp2(15.0 * (1.0 - roughness) + 1.0) * 0.25; - float blinn = pow(cNdotH, shininess) * cNdotL; - blinn *= (shininess + 8.0) * (1.0 / (8.0 * M_PI)); - float intensity = blinn; - - specular_light += light_color * intensity * specular_blob_intensity * attenuation; - -#elif defined(SPECULAR_PHONG) - - vec3 R = normalize(-reflect(L, N)); - float cRdotV = max(0.0, dot(R, V)); - float shininess = exp2(15.0 * (1.0 - roughness) + 1.0) * 0.25; - float phong = pow(cRdotV, shininess); - phong *= (shininess + 8.0) * (1.0 / (8.0 * M_PI)); - float intensity = (phong) / max(4.0 * cNdotV * cNdotL, 0.75); - - specular_light += light_color * intensity * specular_blob_intensity * attenuation; - -#elif defined(SPECULAR_TOON) - - vec3 R = normalize(-reflect(L, N)); - float RdotV = dot(R, V); - float mid = 1.0 - roughness; - mid *= mid; - float intensity = smoothstep(mid - roughness * 0.5, mid + roughness * 0.5, RdotV) * mid; - diffuse_light += light_color * intensity * specular_blob_intensity * attenuation; // write to diffuse_light, as in toon shading you generally want no reflection - -#elif defined(SPECULAR_DISABLED) - // none.. - -#elif defined(SPECULAR_SCHLICK_GGX) - // shlick+ggx as default - -#if defined(LIGHT_USE_ANISOTROPY) - - float alpha_ggx = roughness * roughness; - float aspect = sqrt(1.0 - anisotropy * 0.9); - float ax = alpha_ggx / aspect; - float ay = alpha_ggx * aspect; - float XdotH = dot(T, H); - float YdotH = dot(B, H); - float D = D_GGX_anisotropic(cNdotH, ax, ay, XdotH, YdotH); - float G = G_GGX_anisotropic_2cos(cNdotL, ax, ay, XdotH, YdotH) * G_GGX_anisotropic_2cos(cNdotV, ax, ay, XdotH, YdotH); - -#else - float alpha_ggx = roughness * roughness; - float D = D_GGX(cNdotH, alpha_ggx); - float G = G_GGX_2cos(cNdotL, alpha_ggx) * G_GGX_2cos(cNdotV, alpha_ggx); -#endif - // F - vec3 f0 = F0(metallic, specular, diffuse_color); - float cLdotH5 = SchlickFresnel(cLdotH); - vec3 F = mix(vec3(cLdotH5), vec3(1.0), f0); - - vec3 specular_brdf_NL = cNdotL * D * F * G; - - specular_light += specular_brdf_NL * light_color * specular_blob_intensity * attenuation; -#endif - -#if defined(LIGHT_USE_CLEARCOAT) - -#if !defined(SPECULAR_SCHLICK_GGX) - float cLdotH5 = SchlickFresnel(cLdotH); -#endif - float Dr = GTR1(cNdotH, mix(.1, .001, clearcoat_gloss)); - float Fr = mix(.04, 1.0, cLdotH5); - float Gr = G_GGX_2cos(cNdotL, .25) * G_GGX_2cos(cNdotV, .25); - - float clearcoat_specular_brdf_NL = 0.25 * clearcoat * Gr * Fr * Dr * cNdotL; - - specular_light += clearcoat_specular_brdf_NL * light_color * specular_blob_intensity * attenuation; -#endif - } - -#ifdef USE_SHADOW_TO_OPACITY - alpha = min(alpha, clamp(1.0 - length(attenuation), 0.0, 1.0)); -#endif - -#endif //defined(USE_LIGHT_SHADER_CODE) -} - -float sample_shadow(highp sampler2DShadow shadow, vec2 shadow_pixel_size, vec2 pos, float depth, vec4 clamp_rect) { - -#ifdef SHADOW_MODE_PCF_13 - - float avg = textureProj(shadow, vec4(pos, depth, 1.0)); - avg += textureProj(shadow, vec4(pos + vec2(shadow_pixel_size.x, 0.0), depth, 1.0)); - avg += textureProj(shadow, vec4(pos + vec2(-shadow_pixel_size.x, 0.0), depth, 1.0)); - avg += textureProj(shadow, vec4(pos + vec2(0.0, shadow_pixel_size.y), depth, 1.0)); - avg += textureProj(shadow, vec4(pos + vec2(0.0, -shadow_pixel_size.y), depth, 1.0)); - avg += textureProj(shadow, vec4(pos + vec2(shadow_pixel_size.x, shadow_pixel_size.y), depth, 1.0)); - avg += textureProj(shadow, vec4(pos + vec2(-shadow_pixel_size.x, shadow_pixel_size.y), depth, 1.0)); - avg += textureProj(shadow, vec4(pos + vec2(shadow_pixel_size.x, -shadow_pixel_size.y), depth, 1.0)); - avg += textureProj(shadow, vec4(pos + vec2(-shadow_pixel_size.x, -shadow_pixel_size.y), depth, 1.0)); - avg += textureProj(shadow, vec4(pos + vec2(shadow_pixel_size.x * 2.0, 0.0), depth, 1.0)); - avg += textureProj(shadow, vec4(pos + vec2(-shadow_pixel_size.x * 2.0, 0.0), depth, 1.0)); - avg += textureProj(shadow, vec4(pos + vec2(0.0, shadow_pixel_size.y * 2.0), depth, 1.0)); - avg += textureProj(shadow, vec4(pos + vec2(0.0, -shadow_pixel_size.y * 2.0), depth, 1.0)); - return avg * (1.0 / 13.0); -#endif - -#ifdef SHADOW_MODE_PCF_5 - - float avg = textureProj(shadow, vec4(pos, depth, 1.0)); - avg += textureProj(shadow, vec4(pos + vec2(shadow_pixel_size.x, 0.0), depth, 1.0)); - avg += textureProj(shadow, vec4(pos + vec2(-shadow_pixel_size.x, 0.0), depth, 1.0)); - avg += textureProj(shadow, vec4(pos + vec2(0.0, shadow_pixel_size.y), depth, 1.0)); - avg += textureProj(shadow, vec4(pos + vec2(0.0, -shadow_pixel_size.y), depth, 1.0)); - return avg * (1.0 / 5.0); - -#endif - -#if !defined(SHADOW_MODE_PCF_5) || !defined(SHADOW_MODE_PCF_13) - - return textureProj(shadow, vec4(pos, depth, 1.0)); - -#endif -} - -#ifdef RENDER_DEPTH_DUAL_PARABOLOID - -in highp float dp_clip; - -#endif - -void light_process_omni(int idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 binormal, vec3 tangent, vec3 albedo, vec3 transmission, float roughness, float metallic, float specular, float rim, float rim_tint, float clearcoat, float clearcoat_gloss, float anisotropy, float p_blob_intensity, inout vec3 diffuse_light, inout vec3 specular_light, inout float alpha) { - - vec3 light_rel_vec = omni_lights[idx].light_pos_inv_radius.xyz - vertex; - float light_length = length(light_rel_vec); - float normalized_distance = light_length * omni_lights[idx].light_pos_inv_radius.w; - float omni_attenuation; - if (normalized_distance < 1.0) { - omni_attenuation = pow(1.0 - normalized_distance, omni_lights[idx].light_direction_attenuation.w); - } else { - omni_attenuation = 0.0; - } - vec3 light_attenuation = vec3(omni_attenuation); - -#if !defined(SHADOWS_DISABLED) -#ifdef USE_SHADOW - if (omni_lights[idx].light_params.w > 0.5) { - // there is a shadowmap - - highp vec3 splane = (omni_lights[idx].shadow_matrix * vec4(vertex, 1.0)).xyz; - float shadow_len = length(splane); - splane = normalize(splane); - vec4 clamp_rect = omni_lights[idx].light_clamp; - - if (splane.z >= 0.0) { - - splane.z += 1.0; - - clamp_rect.y += clamp_rect.w; - - } else { - - splane.z = 1.0 - splane.z; - - /* - if (clamp_rect.z < clamp_rect.w) { - clamp_rect.x += clamp_rect.z; - } else { - clamp_rect.y += clamp_rect.w; - } - */ - } - - splane.xy /= splane.z; - splane.xy = splane.xy * 0.5 + 0.5; - splane.z = shadow_len * omni_lights[idx].light_pos_inv_radius.w; - - splane.xy = clamp_rect.xy + splane.xy * clamp_rect.zw; - float shadow = sample_shadow(shadow_atlas, shadow_atlas_pixel_size, splane.xy, splane.z, clamp_rect); - -#ifdef USE_CONTACT_SHADOWS - - if (shadow > 0.01 && omni_lights[idx].shadow_color_contact.a > 0.0) { - - float contact_shadow = contact_shadow_compute(vertex, normalize(light_rel_vec), min(light_length, omni_lights[idx].shadow_color_contact.a)); - shadow = min(shadow, contact_shadow); - } -#endif - light_attenuation *= mix(omni_lights[idx].shadow_color_contact.rgb, vec3(1.0), shadow); - } -#endif //USE_SHADOW -#endif //SHADOWS_DISABLED - light_compute(normal, normalize(light_rel_vec), eye_vec, binormal, tangent, omni_lights[idx].light_color_energy.rgb, light_attenuation, albedo, transmission, omni_lights[idx].light_params.z * p_blob_intensity, roughness, metallic, specular, rim * omni_attenuation, rim_tint, clearcoat, clearcoat_gloss, anisotropy, diffuse_light, specular_light, alpha); -} - -void light_process_spot(int idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 binormal, vec3 tangent, vec3 albedo, vec3 transmission, float roughness, float metallic, float specular, float rim, float rim_tint, float clearcoat, float clearcoat_gloss, float anisotropy, float p_blob_intensity, inout vec3 diffuse_light, inout vec3 specular_light, inout float alpha) { - - vec3 light_rel_vec = spot_lights[idx].light_pos_inv_radius.xyz - vertex; - float light_length = length(light_rel_vec); - float normalized_distance = light_length * spot_lights[idx].light_pos_inv_radius.w; - float spot_attenuation; - if (normalized_distance < 1.0) { - spot_attenuation = pow(1.0 - normalized_distance, spot_lights[idx].light_direction_attenuation.w); - } else { - spot_attenuation = 0.0; - } - vec3 spot_dir = spot_lights[idx].light_direction_attenuation.xyz; - float spot_cutoff = spot_lights[idx].light_params.y; - float scos = max(dot(-normalize(light_rel_vec), spot_dir), spot_cutoff); - float spot_rim = max(0.0001, (1.0 - scos) / (1.0 - spot_cutoff)); - spot_attenuation *= 1.0 - pow(spot_rim, spot_lights[idx].light_params.x); - vec3 light_attenuation = vec3(spot_attenuation); - -#if !defined(SHADOWS_DISABLED) -#ifdef USE_SHADOW - if (spot_lights[idx].light_params.w > 0.5) { - //there is a shadowmap - highp vec4 splane = (spot_lights[idx].shadow_matrix * vec4(vertex, 1.0)); - splane.xyz /= splane.w; - - float shadow = sample_shadow(shadow_atlas, shadow_atlas_pixel_size, splane.xy, splane.z, spot_lights[idx].light_clamp); - -#ifdef USE_CONTACT_SHADOWS - if (shadow > 0.01 && spot_lights[idx].shadow_color_contact.a > 0.0) { - - float contact_shadow = contact_shadow_compute(vertex, normalize(light_rel_vec), min(light_length, spot_lights[idx].shadow_color_contact.a)); - shadow = min(shadow, contact_shadow); - } -#endif - light_attenuation *= mix(spot_lights[idx].shadow_color_contact.rgb, vec3(1.0), shadow); - } -#endif //USE_SHADOW -#endif //SHADOWS_DISABLED - - light_compute(normal, normalize(light_rel_vec), eye_vec, binormal, tangent, spot_lights[idx].light_color_energy.rgb, light_attenuation, albedo, transmission, spot_lights[idx].light_params.z * p_blob_intensity, roughness, metallic, specular, rim * spot_attenuation, rim_tint, clearcoat, clearcoat_gloss, anisotropy, diffuse_light, specular_light, alpha); -} - -void reflection_process(int idx, vec3 vertex, vec3 normal, vec3 binormal, vec3 tangent, float roughness, float anisotropy, vec3 ambient, vec3 skybox, inout highp vec4 reflection_accum, inout highp vec4 ambient_accum) { - - vec3 ref_vec = normalize(reflect(vertex, normal)); - vec3 local_pos = (reflections[idx].local_matrix * vec4(vertex, 1.0)).xyz; - vec3 box_extents = reflections[idx].box_extents.xyz; - - if (any(greaterThan(abs(local_pos), box_extents))) { //out of the reflection box - return; - } - - vec3 inner_pos = abs(local_pos / box_extents); - float blend = max(inner_pos.x, max(inner_pos.y, inner_pos.z)); - //make blend more rounded - blend = mix(length(inner_pos), blend, blend); - blend *= blend; - blend = max(0.0, 1.0 - blend); - - if (reflections[idx].params.x > 0.0) { // compute reflection - - vec3 local_ref_vec = (reflections[idx].local_matrix * vec4(ref_vec, 0.0)).xyz; - - if (reflections[idx].params.w > 0.5) { //box project - - vec3 nrdir = normalize(local_ref_vec); - vec3 rbmax = (box_extents - local_pos) / nrdir; - vec3 rbmin = (-box_extents - local_pos) / nrdir; - - vec3 rbminmax = mix(rbmin, rbmax, greaterThan(nrdir, vec3(0.0, 0.0, 0.0))); - - float fa = min(min(rbminmax.x, rbminmax.y), rbminmax.z); - vec3 posonbox = local_pos + nrdir * fa; - local_ref_vec = posonbox - reflections[idx].box_offset.xyz; - } - - vec4 clamp_rect = reflections[idx].atlas_clamp; - vec3 norm = normalize(local_ref_vec); - norm.xy /= 1.0 + abs(norm.z); - norm.xy = norm.xy * vec2(0.5, 0.25) + vec2(0.5, 0.25); - if (norm.z > 0.0) { - norm.y = 0.5 - norm.y + 0.5; - } - - vec2 atlas_uv = norm.xy * clamp_rect.zw + clamp_rect.xy; - atlas_uv = clamp(atlas_uv, clamp_rect.xy, clamp_rect.xy + clamp_rect.zw); - - highp vec4 reflection; - reflection.rgb = textureLod(reflection_atlas, atlas_uv, roughness * 5.0).rgb; - - if (reflections[idx].params.z < 0.5) { - reflection.rgb = mix(skybox, reflection.rgb, blend); - } - reflection.rgb *= reflections[idx].params.x; - reflection.a = blend; - reflection.rgb *= reflection.a; - - reflection_accum += reflection; - } -#if !defined(USE_LIGHTMAP) && !defined(USE_LIGHTMAP_CAPTURE) - if (reflections[idx].ambient.a > 0.0) { //compute ambient using skybox - - vec3 local_amb_vec = (reflections[idx].local_matrix * vec4(normal, 0.0)).xyz; - - vec3 splane = normalize(local_amb_vec); - vec4 clamp_rect = reflections[idx].atlas_clamp; - - splane.z *= -1.0; - if (splane.z >= 0.0) { - splane.z += 1.0; - clamp_rect.y += clamp_rect.w; - } else { - splane.z = 1.0 - splane.z; - splane.y = -splane.y; - } - - splane.xy /= splane.z; - splane.xy = splane.xy * 0.5 + 0.5; - - splane.xy = splane.xy * clamp_rect.zw + clamp_rect.xy; - splane.xy = clamp(splane.xy, clamp_rect.xy, clamp_rect.xy + clamp_rect.zw); - - highp vec4 ambient_out; - ambient_out.a = blend; - ambient_out.rgb = textureLod(reflection_atlas, splane.xy, 5.0).rgb; - ambient_out.rgb = mix(reflections[idx].ambient.rgb, ambient_out.rgb, reflections[idx].ambient.a); - if (reflections[idx].params.z < 0.5) { - ambient_out.rgb = mix(ambient, ambient_out.rgb, blend); - } - - ambient_out.rgb *= ambient_out.a; - ambient_accum += ambient_out; - } else { - - highp vec4 ambient_out; - ambient_out.a = blend; - ambient_out.rgb = reflections[idx].ambient.rgb; - if (reflections[idx].params.z < 0.5) { - ambient_out.rgb = mix(ambient, ambient_out.rgb, blend); - } - ambient_out.rgb *= ambient_out.a; - ambient_accum += ambient_out; - } -#endif -} - -#ifdef USE_LIGHTMAP -uniform mediump sampler2D lightmap; //texunit:-9 -uniform mediump float lightmap_energy; -#endif - -#ifdef USE_LIGHTMAP_CAPTURE -uniform mediump vec4[12] lightmap_captures; -uniform bool lightmap_capture_sky; - -#endif - -#ifdef USE_GI_PROBES - -uniform mediump sampler3D gi_probe1; //texunit:-9 -uniform highp mat4 gi_probe_xform1; -uniform highp vec3 gi_probe_bounds1; -uniform highp vec3 gi_probe_cell_size1; -uniform highp float gi_probe_multiplier1; -uniform highp float gi_probe_bias1; -uniform highp float gi_probe_normal_bias1; -uniform bool gi_probe_blend_ambient1; - -uniform mediump sampler3D gi_probe2; //texunit:-10 -uniform highp mat4 gi_probe_xform2; -uniform highp vec3 gi_probe_bounds2; -uniform highp vec3 gi_probe_cell_size2; -uniform highp float gi_probe_multiplier2; -uniform highp float gi_probe_bias2; -uniform highp float gi_probe_normal_bias2; -uniform bool gi_probe2_enabled; -uniform bool gi_probe_blend_ambient2; - -vec3 voxel_cone_trace(mediump sampler3D probe, vec3 cell_size, vec3 pos, vec3 ambient, bool blend_ambient, vec3 direction, float tan_half_angle, float max_distance, float p_bias) { - - float dist = p_bias; //1.0; //dot(direction,mix(vec3(-1.0),vec3(1.0),greaterThan(direction,vec3(0.0))))*2.0; - float alpha = 0.0; - vec3 color = vec3(0.0); - - while (dist < max_distance && alpha < 0.95) { - float diameter = max(1.0, 2.0 * tan_half_angle * dist); - vec4 scolor = textureLod(probe, (pos + dist * direction) * cell_size, log2(diameter)); - float a = (1.0 - alpha); - color += scolor.rgb * a; - alpha += a * scolor.a; - dist += diameter * 0.5; - } - - if (blend_ambient) { - color.rgb = mix(ambient, color.rgb, min(1.0, alpha / 0.95)); - } - - return color; -} - -void gi_probe_compute(mediump sampler3D probe, mat4 probe_xform, vec3 bounds, vec3 cell_size, vec3 pos, vec3 ambient, vec3 environment, bool blend_ambient, float multiplier, mat3 normal_mtx, vec3 ref_vec, float roughness, float p_bias, float p_normal_bias, inout vec4 out_spec, inout vec4 out_diff) { - - vec3 probe_pos = (probe_xform * vec4(pos, 1.0)).xyz; - vec3 ref_pos = (probe_xform * vec4(pos + ref_vec, 1.0)).xyz; - ref_vec = normalize(ref_pos - probe_pos); - - probe_pos += (probe_xform * vec4(normal_mtx[2], 0.0)).xyz * p_normal_bias; - - /* out_diff.rgb = voxel_cone_trace(probe,cell_size,probe_pos,normalize((probe_xform * vec4(ref_vec,0.0)).xyz),0.0 ,100.0); - out_diff.a = 1.0; - return;*/ - //out_diff = vec4(textureLod(probe,probe_pos*cell_size,3.0).rgb,1.0); - //return; - - //this causes corrupted pixels, i have no idea why.. - if (any(bvec2(any(lessThan(probe_pos, vec3(0.0))), any(greaterThan(probe_pos, bounds))))) { - return; - } - - vec3 blendv = abs(probe_pos / bounds * 2.0 - 1.0); - float blend = clamp(1.0 - max(blendv.x, max(blendv.y, blendv.z)), 0.0, 1.0); - //float blend=1.0; - - float max_distance = length(bounds); - - //radiance -#ifdef VCT_QUALITY_HIGH - -#define MAX_CONE_DIRS 6 - vec3 cone_dirs[MAX_CONE_DIRS] = vec3[]( - vec3(0.0, 0.0, 1.0), - vec3(0.866025, 0.0, 0.5), - vec3(0.267617, 0.823639, 0.5), - vec3(-0.700629, 0.509037, 0.5), - vec3(-0.700629, -0.509037, 0.5), - vec3(0.267617, -0.823639, 0.5)); - - float cone_weights[MAX_CONE_DIRS] = float[](0.25, 0.15, 0.15, 0.15, 0.15, 0.15); - float cone_angle_tan = 0.577; - float min_ref_tan = 0.0; -#else - -#define MAX_CONE_DIRS 4 - - vec3 cone_dirs[MAX_CONE_DIRS] = vec3[]( - vec3(0.707107, 0.0, 0.707107), - vec3(0.0, 0.707107, 0.707107), - vec3(-0.707107, 0.0, 0.707107), - vec3(0.0, -0.707107, 0.707107)); - - float cone_weights[MAX_CONE_DIRS] = float[](0.25, 0.25, 0.25, 0.25); - float cone_angle_tan = 0.98269; - max_distance *= 0.5; - float min_ref_tan = 0.2; - -#endif - vec3 light = vec3(0.0); - for (int i = 0; i < MAX_CONE_DIRS; i++) { - - vec3 dir = normalize((probe_xform * vec4(pos + normal_mtx * cone_dirs[i], 1.0)).xyz - probe_pos); - light += cone_weights[i] * voxel_cone_trace(probe, cell_size, probe_pos, ambient, blend_ambient, dir, cone_angle_tan, max_distance, p_bias); - } - - light *= multiplier; - - out_diff += vec4(light * blend, blend); - - //irradiance - - vec3 irr_light = voxel_cone_trace(probe, cell_size, probe_pos, environment, blend_ambient, ref_vec, max(min_ref_tan, tan(roughness * 0.5 * M_PI * 0.99)), max_distance, p_bias); - - irr_light *= multiplier; - //irr_light=vec3(0.0); - - out_spec += vec4(irr_light * blend, blend); -} - -void gi_probes_compute(vec3 pos, vec3 normal, float roughness, inout vec3 out_specular, inout vec3 out_ambient) { - - roughness = roughness * roughness; - - vec3 ref_vec = normalize(reflect(normalize(pos), normal)); - - //find arbitrary tangent and bitangent, then build a matrix - vec3 v0 = abs(normal.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(0.0, 1.0, 0.0); - vec3 tangent = normalize(cross(v0, normal)); - vec3 bitangent = normalize(cross(tangent, normal)); - mat3 normal_mat = mat3(tangent, bitangent, normal); - - vec4 diff_accum = vec4(0.0); - vec4 spec_accum = vec4(0.0); - - vec3 ambient = out_ambient; - out_ambient = vec3(0.0); - - vec3 environment = out_specular; - - out_specular = vec3(0.0); - - gi_probe_compute(gi_probe1, gi_probe_xform1, gi_probe_bounds1, gi_probe_cell_size1, pos, ambient, environment, gi_probe_blend_ambient1, gi_probe_multiplier1, normal_mat, ref_vec, roughness, gi_probe_bias1, gi_probe_normal_bias1, spec_accum, diff_accum); - - if (gi_probe2_enabled) { - - gi_probe_compute(gi_probe2, gi_probe_xform2, gi_probe_bounds2, gi_probe_cell_size2, pos, ambient, environment, gi_probe_blend_ambient2, gi_probe_multiplier2, normal_mat, ref_vec, roughness, gi_probe_bias2, gi_probe_normal_bias2, spec_accum, diff_accum); - } - - if (diff_accum.a > 0.0) { - diff_accum.rgb /= diff_accum.a; - } - - if (spec_accum.a > 0.0) { - spec_accum.rgb /= spec_accum.a; - } - - out_specular += spec_accum.rgb; - out_ambient += diff_accum.rgb; -} - -#endif - -void main() { - -#ifdef RENDER_DEPTH_DUAL_PARABOLOID - - if (dp_clip > 0.0) - discard; -#endif - - //lay out everything, whathever is unused is optimized away anyway - highp vec3 vertex = vertex_interp; - vec3 view = -normalize(vertex_interp); - vec3 albedo = vec3(1.0); - vec3 transmission = vec3(0.0); - float metallic = 0.0; - float specular = 0.5; - vec3 emission = vec3(0.0); - float roughness = 1.0; - float rim = 0.0; - float rim_tint = 0.0; - float clearcoat = 0.0; - float clearcoat_gloss = 0.0; - float anisotropy = 0.0; - vec2 anisotropy_flow = vec2(1.0, 0.0); - -#if defined(ENABLE_AO) - float ao = 1.0; - float ao_light_affect = 0.0; -#endif - - float alpha = 1.0; - -#if defined(ALPHA_SCISSOR_USED) - float alpha_scissor = 0.5; -#endif - -#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) || defined(LIGHT_USE_ANISOTROPY) - vec3 binormal = normalize(binormal_interp); - vec3 tangent = normalize(tangent_interp); -#else - vec3 binormal = vec3(0.0); - vec3 tangent = vec3(0.0); -#endif - vec3 normal = normalize(normal_interp); - -#if defined(DO_SIDE_CHECK) - if (!gl_FrontFacing) { - normal = -normal; - } -#endif - -#if defined(ENABLE_UV_INTERP) - vec2 uv = uv_interp; -#endif - -#if defined(ENABLE_UV2_INTERP) || defined(USE_LIGHTMAP) - vec2 uv2 = uv2_interp; -#endif - -#if defined(ENABLE_COLOR_INTERP) - vec4 color = color_interp; -#endif - -#if defined(ENABLE_NORMALMAP) - - vec3 normalmap = vec3(0.5); -#endif - - float normaldepth = 1.0; - -#if defined(SCREEN_UV_USED) - vec2 screen_uv = gl_FragCoord.xy * screen_pixel_size; -#endif - -#if defined(ENABLE_SSS) - float sss_strength = 0.0; -#endif - - { - /* clang-format off */ - -FRAGMENT_SHADER_CODE - - /* clang-format on */ - } - -#if !defined(USE_SHADOW_TO_OPACITY) - -#if defined(ALPHA_SCISSOR_USED) - if (alpha < alpha_scissor) { - discard; - } -#endif // ALPHA_SCISSOR_USED - -#ifdef USE_OPAQUE_PREPASS - - if (alpha < opaque_prepass_threshold) { - discard; - } - -#endif // USE_OPAQUE_PREPASS - -#endif // !USE_SHADOW_TO_OPACITY - -#if defined(ENABLE_NORMALMAP) - - normalmap.xy = normalmap.xy * 2.0 - 1.0; - normalmap.z = sqrt(max(0.0, 1.0 - dot(normalmap.xy, normalmap.xy))); //always ignore Z, as it can be RG packed, Z may be pos/neg, etc. - - normal = normalize(mix(normal, tangent * normalmap.x + binormal * normalmap.y + normal * normalmap.z, normaldepth)); - -#endif - -#if defined(LIGHT_USE_ANISOTROPY) - - if (anisotropy > 0.01) { - //rotation matrix - mat3 rot = mat3(tangent, binormal, normal); - //make local to space - tangent = normalize(rot * vec3(anisotropy_flow.x, anisotropy_flow.y, 0.0)); - binormal = normalize(rot * vec3(-anisotropy_flow.y, anisotropy_flow.x, 0.0)); - } - -#endif - -#ifdef ENABLE_CLIP_ALPHA - if (albedo.a < 0.99) { - //used for doublepass and shadowmapping - discard; - } -#endif - - /////////////////////// LIGHTING ////////////////////////////// - - //apply energy conservation - -#ifdef USE_VERTEX_LIGHTING - - vec3 specular_light = specular_light_interp.rgb; - vec3 diffuse_light = diffuse_light_interp.rgb; -#else - - vec3 specular_light = vec3(0.0, 0.0, 0.0); - vec3 diffuse_light = vec3(0.0, 0.0, 0.0); - -#endif - - vec3 ambient_light; - vec3 env_reflection_light = vec3(0.0, 0.0, 0.0); - - vec3 eye_vec = view; - - // IBL precalculations - float ndotv = clamp(dot(normal, eye_vec), 0.0, 1.0); - vec3 f0 = F0(metallic, specular, albedo); - vec3 F = f0 + (max(vec3(1.0 - roughness), f0) - f0) * pow(1.0 - ndotv, 5.0); - -#ifdef USE_RADIANCE_MAP - -#ifdef AMBIENT_LIGHT_DISABLED - ambient_light = vec3(0.0, 0.0, 0.0); -#else - { - - { //read radiance from dual paraboloid - - vec3 ref_vec = reflect(-eye_vec, normal); - ref_vec = normalize((radiance_inverse_xform * vec4(ref_vec, 0.0)).xyz); - vec3 radiance = textureDualParaboloid(radiance_map, ref_vec, roughness) * bg_energy; - env_reflection_light = radiance; - } - } -#ifndef USE_LIGHTMAP - { - - vec3 norm = normal; - norm = normalize((radiance_inverse_xform * vec4(norm, 0.0)).xyz); - norm.xy /= 1.0 + abs(norm.z); - norm.xy = norm.xy * vec2(0.5, 0.25) + vec2(0.5, 0.25); - if (norm.z > 0.0) { - norm.y = 0.5 - norm.y + 0.5; - } - - vec3 env_ambient = texture(irradiance_map, norm.xy).rgb * bg_energy; - env_ambient *= 1.0 - F; - - ambient_light = mix(ambient_light_color.rgb, env_ambient, radiance_ambient_contribution); - } -#endif -#endif //AMBIENT_LIGHT_DISABLED - -#else - -#ifdef AMBIENT_LIGHT_DISABLED - ambient_light = vec3(0.0, 0.0, 0.0); -#else - ambient_light = ambient_light_color.rgb; - env_reflection_light = bg_color.rgb * bg_energy; -#endif //AMBIENT_LIGHT_DISABLED - -#endif - - ambient_light *= ambient_energy; - - float specular_blob_intensity = 1.0; - -#if defined(SPECULAR_TOON) - specular_blob_intensity *= specular * 2.0; -#endif - -#ifdef USE_GI_PROBES - gi_probes_compute(vertex, normal, roughness, env_reflection_light, ambient_light); - -#endif - -#ifdef USE_LIGHTMAP - ambient_light = texture(lightmap, uv2).rgb * lightmap_energy; -#endif - -#ifdef USE_LIGHTMAP_CAPTURE - { - vec3 cone_dirs[12] = vec3[]( - vec3(0.0, 0.0, 1.0), - vec3(0.866025, 0.0, 0.5), - vec3(0.267617, 0.823639, 0.5), - vec3(-0.700629, 0.509037, 0.5), - vec3(-0.700629, -0.509037, 0.5), - vec3(0.267617, -0.823639, 0.5), - vec3(0.0, 0.0, -1.0), - vec3(0.866025, 0.0, -0.5), - vec3(0.267617, 0.823639, -0.5), - vec3(-0.700629, 0.509037, -0.5), - vec3(-0.700629, -0.509037, -0.5), - vec3(0.267617, -0.823639, -0.5)); - - vec3 local_normal = normalize(camera_matrix * vec4(normal, 0.0)).xyz; - vec4 captured = vec4(0.0); - float sum = 0.0; - for (int i = 0; i < 12; i++) { - float amount = max(0.0, dot(local_normal, cone_dirs[i])); //not correct, but creates a nice wrap around effect - captured += lightmap_captures[i] * amount; - sum += amount; - } - - captured /= sum; - - if (lightmap_capture_sky) { - ambient_light = mix(ambient_light, captured.rgb, captured.a); - } else { - ambient_light = captured.rgb; - } - } -#endif - -#ifdef USE_FORWARD_LIGHTING - - highp vec4 reflection_accum = vec4(0.0, 0.0, 0.0, 0.0); - highp vec4 ambient_accum = vec4(0.0, 0.0, 0.0, 0.0); - for (int i = 0; i < reflection_count; i++) { - reflection_process(reflection_indices[i], vertex, normal, binormal, tangent, roughness, anisotropy, ambient_light, env_reflection_light, reflection_accum, ambient_accum); - } - - if (reflection_accum.a > 0.0) { - specular_light += reflection_accum.rgb / reflection_accum.a; - } else { - specular_light += env_reflection_light; - } -#if !defined(USE_LIGHTMAP) && !defined(USE_LIGHTMAP_CAPTURE) - if (ambient_accum.a > 0.0) { - ambient_light = ambient_accum.rgb / ambient_accum.a; - } -#endif -#endif - - { - -#if defined(DIFFUSE_TOON) - //simplify for toon, as - specular_light *= specular * metallic * albedo * 2.0; -#else - - // scales the specular reflections, needs to be be computed before lighting happens, - // but after environment, GI, and reflection probes are added - // Environment brdf approximation (Lazarov 2013) - // see https://www.unrealengine.com/en-US/blog/physically-based-shading-on-mobile - const vec4 c0 = vec4(-1.0, -0.0275, -0.572, 0.022); - const vec4 c1 = vec4(1.0, 0.0425, 1.04, -0.04); - vec4 r = roughness * c0 + c1; - float a004 = min(r.x * r.x, exp2(-9.28 * ndotv)) * r.x + r.y; - vec2 env = vec2(-1.04, 1.04) * a004 + r.zw; - specular_light *= env.x * F + env.y; -#endif - } - -#if defined(USE_LIGHT_DIRECTIONAL) - - vec3 light_attenuation = vec3(1.0); - - float depth_z = -vertex.z; -#ifdef LIGHT_DIRECTIONAL_SHADOW -#if !defined(SHADOWS_DISABLED) - -#ifdef LIGHT_USE_PSSM4 - if (depth_z < shadow_split_offsets.w) { -#elif defined(LIGHT_USE_PSSM2) - if (depth_z < shadow_split_offsets.y) { -#else - if (depth_z < shadow_split_offsets.x) { -#endif //LIGHT_USE_PSSM4 - - vec3 pssm_coord; - float pssm_fade = 0.0; - -#ifdef LIGHT_USE_PSSM_BLEND - float pssm_blend; - vec3 pssm_coord2; - bool use_blend = true; -#endif - -#ifdef LIGHT_USE_PSSM4 - - if (depth_z < shadow_split_offsets.y) { - - if (depth_z < shadow_split_offsets.x) { - - highp vec4 splane = (shadow_matrix1 * vec4(vertex, 1.0)); - pssm_coord = splane.xyz / splane.w; - -#if defined(LIGHT_USE_PSSM_BLEND) - - splane = (shadow_matrix2 * vec4(vertex, 1.0)); - pssm_coord2 = splane.xyz / splane.w; - pssm_blend = smoothstep(0.0, shadow_split_offsets.x, depth_z); -#endif - - } else { - - highp vec4 splane = (shadow_matrix2 * vec4(vertex, 1.0)); - pssm_coord = splane.xyz / splane.w; - -#if defined(LIGHT_USE_PSSM_BLEND) - splane = (shadow_matrix3 * vec4(vertex, 1.0)); - pssm_coord2 = splane.xyz / splane.w; - pssm_blend = smoothstep(shadow_split_offsets.x, shadow_split_offsets.y, depth_z); -#endif - } - } else { - - if (depth_z < shadow_split_offsets.z) { - - highp vec4 splane = (shadow_matrix3 * vec4(vertex, 1.0)); - pssm_coord = splane.xyz / splane.w; - -#if defined(LIGHT_USE_PSSM_BLEND) - splane = (shadow_matrix4 * vec4(vertex, 1.0)); - pssm_coord2 = splane.xyz / splane.w; - pssm_blend = smoothstep(shadow_split_offsets.y, shadow_split_offsets.z, depth_z); -#endif - - } else { - - highp vec4 splane = (shadow_matrix4 * vec4(vertex, 1.0)); - pssm_coord = splane.xyz / splane.w; - pssm_fade = smoothstep(shadow_split_offsets.z, shadow_split_offsets.w, depth_z); - -#if defined(LIGHT_USE_PSSM_BLEND) - use_blend = false; - -#endif - } - } - -#endif //LIGHT_USE_PSSM4 - -#ifdef LIGHT_USE_PSSM2 - - if (depth_z < shadow_split_offsets.x) { - - highp vec4 splane = (shadow_matrix1 * vec4(vertex, 1.0)); - pssm_coord = splane.xyz / splane.w; - -#if defined(LIGHT_USE_PSSM_BLEND) - - splane = (shadow_matrix2 * vec4(vertex, 1.0)); - pssm_coord2 = splane.xyz / splane.w; - pssm_blend = smoothstep(0.0, shadow_split_offsets.x, depth_z); -#endif - - } else { - highp vec4 splane = (shadow_matrix2 * vec4(vertex, 1.0)); - pssm_coord = splane.xyz / splane.w; - pssm_fade = smoothstep(shadow_split_offsets.x, shadow_split_offsets.y, depth_z); -#if defined(LIGHT_USE_PSSM_BLEND) - use_blend = false; - -#endif - } - -#endif //LIGHT_USE_PSSM2 - -#if !defined(LIGHT_USE_PSSM4) && !defined(LIGHT_USE_PSSM2) - { //regular orthogonal - highp vec4 splane = (shadow_matrix1 * vec4(vertex, 1.0)); - pssm_coord = splane.xyz / splane.w; - } -#endif - - //one one sample - - float shadow = sample_shadow(directional_shadow, directional_shadow_pixel_size, pssm_coord.xy, pssm_coord.z, light_clamp); - -#if defined(LIGHT_USE_PSSM_BLEND) - - if (use_blend) { - shadow = mix(shadow, sample_shadow(directional_shadow, directional_shadow_pixel_size, pssm_coord2.xy, pssm_coord2.z, light_clamp), pssm_blend); - } -#endif - -#ifdef USE_CONTACT_SHADOWS - if (shadow > 0.01 && shadow_color_contact.a > 0.0) { - - float contact_shadow = contact_shadow_compute(vertex, -light_direction_attenuation.xyz, shadow_color_contact.a); - shadow = min(shadow, contact_shadow); - } -#endif - light_attenuation = mix(mix(shadow_color_contact.rgb, vec3(1.0), shadow), vec3(1.0), pssm_fade); - } - -#endif // !defined(SHADOWS_DISABLED) -#endif //LIGHT_DIRECTIONAL_SHADOW - -#ifdef USE_VERTEX_LIGHTING - diffuse_light *= mix(vec3(1.0), light_attenuation, diffuse_light_interp.a); - specular_light *= mix(vec3(1.0), light_attenuation, specular_light_interp.a); - -#else - light_compute(normal, -light_direction_attenuation.xyz, eye_vec, binormal, tangent, light_color_energy.rgb, light_attenuation, albedo, transmission, light_params.z * specular_blob_intensity, roughness, metallic, specular, rim, rim_tint, clearcoat, clearcoat_gloss, anisotropy, diffuse_light, specular_light, alpha); -#endif - -#endif //#USE_LIGHT_DIRECTIONAL - -#ifdef USE_FORWARD_LIGHTING - -#ifdef USE_VERTEX_LIGHTING - - diffuse_light *= albedo; -#else - - for (int i = 0; i < omni_light_count; i++) { - light_process_omni(omni_light_indices[i], vertex, eye_vec, normal, binormal, tangent, albedo, transmission, roughness, metallic, specular, rim, rim_tint, clearcoat, clearcoat_gloss, anisotropy, specular_blob_intensity, diffuse_light, specular_light, alpha); - } - - for (int i = 0; i < spot_light_count; i++) { - light_process_spot(spot_light_indices[i], vertex, eye_vec, normal, binormal, tangent, albedo, transmission, roughness, metallic, specular, rim, rim_tint, clearcoat, clearcoat_gloss, anisotropy, specular_blob_intensity, diffuse_light, specular_light, alpha); - } - -#endif //USE_VERTEX_LIGHTING - -#endif - -#ifdef USE_SHADOW_TO_OPACITY - alpha = min(alpha, clamp(length(ambient_light), 0.0, 1.0)); - -#if defined(ALPHA_SCISSOR_USED) - if (alpha < alpha_scissor) { - discard; - } -#endif // ALPHA_SCISSOR_USED - -#ifdef USE_OPAQUE_PREPASS - - if (alpha < opaque_prepass_threshold) { - discard; - } - -#endif // USE_OPAQUE_PREPASS - -#endif // USE_SHADOW_TO_OPACITY - -#ifdef RENDER_DEPTH -//nothing happens, so a tree-ssa optimizer will result in no fragment shader :) -#else - - specular_light *= reflection_multiplier; - ambient_light *= albedo; //ambient must be multiplied by albedo at the end - -#if defined(ENABLE_AO) - ambient_light *= ao; - ao_light_affect = mix(1.0, ao, ao_light_affect); - specular_light *= ao_light_affect; - diffuse_light *= ao_light_affect; -#endif - - // base color remapping - diffuse_light *= 1.0 - metallic; // TODO: avoid all diffuse and ambient light calculations when metallic == 1 up to this point - ambient_light *= 1.0 - metallic; - - if (fog_color_enabled.a > 0.5) { - - float fog_amount = 0.0; - -#ifdef USE_LIGHT_DIRECTIONAL - - vec3 fog_color = mix(fog_color_enabled.rgb, fog_sun_color_amount.rgb, fog_sun_color_amount.a * pow(max(dot(normalize(vertex), -light_direction_attenuation.xyz), 0.0), 8.0)); -#else - - vec3 fog_color = fog_color_enabled.rgb; -#endif - - //apply fog - - if (fog_depth_enabled) { - float fog_far = fog_depth_end > 0.0 ? fog_depth_end : z_far; - - float fog_z = smoothstep(fog_depth_begin, fog_far, length(vertex)); - - fog_amount = pow(fog_z, fog_depth_curve) * fog_density; - if (fog_transmit_enabled) { - vec3 total_light = emission + ambient_light + specular_light + diffuse_light; - float transmit = pow(fog_z, fog_transmit_curve); - fog_color = mix(max(total_light, fog_color), fog_color, transmit); - } - } - - if (fog_height_enabled) { - float y = (camera_matrix * vec4(vertex, 1.0)).y; - fog_amount = max(fog_amount, pow(smoothstep(fog_height_min, fog_height_max, y), fog_height_curve)); - } - - float rev_amount = 1.0 - fog_amount; - - emission = emission * rev_amount + fog_color * fog_amount; - ambient_light *= rev_amount; - specular_light *= rev_amount; - diffuse_light *= rev_amount; - } - -#ifdef USE_MULTIPLE_RENDER_TARGETS - -#ifdef SHADELESS - diffuse_buffer = vec4(albedo.rgb, 0.0); - specular_buffer = vec4(0.0); - -#else - - //approximate ambient scale for SSAO, since we will lack full ambient - float max_emission = max(emission.r, max(emission.g, emission.b)); - float max_ambient = max(ambient_light.r, max(ambient_light.g, ambient_light.b)); - float max_diffuse = max(diffuse_light.r, max(diffuse_light.g, diffuse_light.b)); - float total_ambient = max_ambient + max_diffuse + max_emission; - float ambient_scale = (total_ambient > 0.0) ? (max_ambient + ambient_occlusion_affect_light * max_diffuse) / total_ambient : 0.0; - -#if defined(ENABLE_AO) - ambient_scale = mix(0.0, ambient_scale, ambient_occlusion_affect_ao_channel); -#endif - diffuse_buffer = vec4(emission + diffuse_light + ambient_light, ambient_scale); - specular_buffer = vec4(specular_light, metallic); - -#endif //SHADELESS - - normal_mr_buffer = vec4(normalize(normal) * 0.5 + 0.5, roughness); - -#if defined(ENABLE_SSS) - sss_buffer = sss_strength; -#endif - -#else //USE_MULTIPLE_RENDER_TARGETS - -#ifdef SHADELESS - frag_color = vec4(albedo, alpha); -#else - frag_color = vec4(emission + ambient_light + diffuse_light + specular_light, alpha); -#endif //SHADELESS - -#endif //USE_MULTIPLE_RENDER_TARGETS - -#endif //RENDER_DEPTH -} diff --git a/drivers/gles3/shaders/screen_space_reflection.glsl b/drivers/gles3/shaders/screen_space_reflection.glsl deleted file mode 100644 index 39f1ea6155..0000000000 --- a/drivers/gles3/shaders/screen_space_reflection.glsl +++ /dev/null @@ -1,286 +0,0 @@ -/* clang-format off */ -[vertex] - -layout(location = 0) in highp vec4 vertex_attrib; -/* clang-format on */ -layout(location = 4) in vec2 uv_in; - -out vec2 uv_interp; -out vec2 pos_interp; - -void main() { - - uv_interp = uv_in; - gl_Position = vertex_attrib; - pos_interp.xy = gl_Position.xy; -} - -/* clang-format off */ -[fragment] - -in vec2 uv_interp; -/* clang-format on */ -in vec2 pos_interp; - -uniform sampler2D source_diffuse; //texunit:0 -uniform sampler2D source_normal_roughness; //texunit:1 -uniform sampler2D source_depth; //texunit:2 - -uniform float camera_z_near; -uniform float camera_z_far; - -uniform vec2 viewport_size; -uniform vec2 pixel_size; - -uniform float filter_mipmap_levels; - -uniform mat4 inverse_projection; -uniform mat4 projection; - -uniform int num_steps; -uniform float depth_tolerance; -uniform float distance_fade; -uniform float curve_fade_in; - -layout(location = 0) out vec4 frag_color; - -vec2 view_to_screen(vec3 view_pos, out float w) { - vec4 projected = projection * vec4(view_pos, 1.0); - projected.xyz /= projected.w; - projected.xy = projected.xy * 0.5 + 0.5; - w = projected.w; - return projected.xy; -} - -#define M_PI 3.14159265359 - -void main() { - - vec4 diffuse = texture(source_diffuse, uv_interp); - vec4 normal_roughness = texture(source_normal_roughness, uv_interp); - - vec3 normal; - normal = normal_roughness.xyz * 2.0 - 1.0; - - float roughness = normal_roughness.w; - - float depth_tex = texture(source_depth, uv_interp).r; - - vec4 world_pos = inverse_projection * vec4(uv_interp * 2.0 - 1.0, depth_tex * 2.0 - 1.0, 1.0); - vec3 vertex = world_pos.xyz / world_pos.w; - - vec3 view_dir = normalize(vertex); - vec3 ray_dir = normalize(reflect(view_dir, normal)); - - if (dot(ray_dir, normal) < 0.001) { - frag_color = vec4(0.0); - return; - } - //ray_dir = normalize(view_dir - normal * dot(normal,view_dir) * 2.0); - //ray_dir = normalize(vec3(1.0, 1.0, -1.0)); - - //////////////// - - // make ray length and clip it against the near plane (don't want to trace beyond visible) - float ray_len = (vertex.z + ray_dir.z * camera_z_far) > -camera_z_near ? (-camera_z_near - vertex.z) / ray_dir.z : camera_z_far; - vec3 ray_end = vertex + ray_dir * ray_len; - - float w_begin; - vec2 vp_line_begin = view_to_screen(vertex, w_begin); - float w_end; - vec2 vp_line_end = view_to_screen(ray_end, w_end); - vec2 vp_line_dir = vp_line_end - vp_line_begin; - - // we need to interpolate w along the ray, to generate perspective correct reflections - w_begin = 1.0 / w_begin; - w_end = 1.0 / w_end; - - float z_begin = vertex.z * w_begin; - float z_end = ray_end.z * w_end; - - vec2 line_begin = vp_line_begin / pixel_size; - vec2 line_dir = vp_line_dir / pixel_size; - float z_dir = z_end - z_begin; - float w_dir = w_end - w_begin; - - // clip the line to the viewport edges - - float scale_max_x = min(1.0, 0.99 * (1.0 - vp_line_begin.x) / max(1e-5, vp_line_dir.x)); - float scale_max_y = min(1.0, 0.99 * (1.0 - vp_line_begin.y) / max(1e-5, vp_line_dir.y)); - float scale_min_x = min(1.0, 0.99 * vp_line_begin.x / max(1e-5, -vp_line_dir.x)); - float scale_min_y = min(1.0, 0.99 * vp_line_begin.y / max(1e-5, -vp_line_dir.y)); - float line_clip = min(scale_max_x, scale_max_y) * min(scale_min_x, scale_min_y); - line_dir *= line_clip; - z_dir *= line_clip; - w_dir *= line_clip; - - // clip z and w advance to line advance - vec2 line_advance = normalize(line_dir); // down to pixel - float step_size = length(line_advance) / length(line_dir); - float z_advance = z_dir * step_size; // adapt z advance to line advance - float w_advance = w_dir * step_size; // adapt w advance to line advance - - // make line advance faster if direction is closer to pixel edges (this avoids sampling the same pixel twice) - float advance_angle_adj = 1.0 / max(abs(line_advance.x), abs(line_advance.y)); - line_advance *= advance_angle_adj; // adapt z advance to line advance - z_advance *= advance_angle_adj; - w_advance *= advance_angle_adj; - - vec2 pos = line_begin; - float z = z_begin; - float w = w_begin; - float z_from = z / w; - float z_to = z_from; - float depth; - vec2 prev_pos = pos; - - bool found = false; - - float steps_taken = 0.0; - - for (int i = 0; i < num_steps; i++) { - - pos += line_advance; - z += z_advance; - w += w_advance; - - // convert to linear depth - - depth = texture(source_depth, pos * pixel_size).r * 2.0 - 1.0; -#ifdef USE_ORTHOGONAL_PROJECTION - depth = ((depth + (camera_z_far + camera_z_near) / (camera_z_far - camera_z_near)) * (camera_z_far - camera_z_near)) / 2.0; -#else - depth = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - depth * (camera_z_far - camera_z_near)); -#endif - depth = -depth; - - z_from = z_to; - z_to = z / w; - - if (depth > z_to) { - // if depth was surpassed - if (depth <= max(z_to, z_from) + depth_tolerance) { - // check the depth tolerance - found = true; - } - break; - } - - steps_taken += 1.0; - prev_pos = pos; - } - - if (found) { - - float margin_blend = 1.0; - - vec2 margin = vec2((viewport_size.x + viewport_size.y) * 0.5 * 0.05); // make a uniform margin - if (any(bvec4(lessThan(pos, -margin), greaterThan(pos, viewport_size + margin)))) { - // clip outside screen + margin - frag_color = vec4(0.0); - return; - } - - { - //blend fading out towards external margin - vec2 margin_grad = mix(pos - viewport_size, -pos, lessThan(pos, vec2(0.0))); - margin_blend = 1.0 - smoothstep(0.0, margin.x, max(margin_grad.x, margin_grad.y)); - //margin_blend = 1.0; - } - - vec2 final_pos; - float grad; - grad = steps_taken / float(num_steps); - float initial_fade = curve_fade_in == 0.0 ? 1.0 : pow(clamp(grad, 0.0, 1.0), curve_fade_in); - float fade = pow(clamp(1.0 - grad, 0.0, 1.0), distance_fade) * initial_fade; - final_pos = pos; - -#ifdef REFLECT_ROUGHNESS - - vec4 final_color; - // if roughness is enabled, do screen space cone tracing - if (roughness > 0.001) { - /////////////////////////////////////////////////////////////////////////////////////// - // use a blurred version (in consecutive mipmaps) of the screen to simulate roughness - - float gloss = 1.0 - roughness; - float cone_angle = roughness * M_PI * 0.5; - vec2 cone_dir = final_pos - line_begin; - float cone_len = length(cone_dir); - cone_dir = normalize(cone_dir); // will be used normalized from now on - float max_mipmap = filter_mipmap_levels - 1.0; - float gloss_mult = gloss; - - float rem_alpha = 1.0; - final_color = vec4(0.0); - - for (int i = 0; i < 7; i++) { - - float op_len = 2.0 * tan(cone_angle) * cone_len; // opposite side of iso triangle - float radius; - { - // fit to sphere inside cone (sphere ends at end of cone), something like this: - // ___ - // \O/ - // V - // - // as it avoids bleeding from beyond the reflection as much as possible. As a plus - // it also makes the rough reflection more elongated. - float a = op_len; - float h = cone_len; - float a2 = a * a; - float fh2 = 4.0f * h * h; - radius = (a * (sqrt(a2 + fh2) - a)) / (4.0f * h); - } - - // find the place where screen must be sampled - vec2 sample_pos = (line_begin + cone_dir * (cone_len - radius)) * pixel_size; - // radius is in pixels, so it's natural that log2(radius) maps to the right mipmap for the amount of pixels - float mipmap = clamp(log2(radius), 0.0, max_mipmap); - //mipmap = max(mipmap - 1.0, 0.0); - - // do sampling - - vec4 sample_color; - { - sample_color = textureLod(source_diffuse, sample_pos, mipmap); - } - - // multiply by gloss - sample_color.rgb *= gloss_mult; - sample_color.a = gloss_mult; - - rem_alpha -= sample_color.a; - if (rem_alpha < 0.0) { - sample_color.rgb *= (1.0 - abs(rem_alpha)); - } - - final_color += sample_color; - - if (final_color.a >= 0.95) { - // This code of accumulating gloss and aborting on near one - // makes sense when you think of cone tracing. - // Think of it as if roughness was 0, then we could abort on the first - // iteration. For lesser roughness values, we need more iterations, but - // each needs to have less influence given the sphere is smaller - break; - } - - cone_len -= radius * 2.0; // go to next (smaller) circle. - - gloss_mult *= gloss; - } - } else { - final_color = textureLod(source_diffuse, final_pos * pixel_size, 0.0); - } - - frag_color = vec4(final_color.rgb, fade * margin_blend); - -#else - frag_color = vec4(textureLod(source_diffuse, final_pos * pixel_size, 0.0).rgb, fade * margin_blend); -#endif - - } else { - frag_color = vec4(0.0, 0.0, 0.0, 0.0); - } -} diff --git a/drivers/gles3/shaders/ssao.glsl b/drivers/gles3/shaders/ssao.glsl deleted file mode 100644 index d9cdc3fc1f..0000000000 --- a/drivers/gles3/shaders/ssao.glsl +++ /dev/null @@ -1,277 +0,0 @@ -/* clang-format off */ -[vertex] - -layout(location = 0) in highp vec4 vertex_attrib; -/* clang-format on */ - -void main() { - - gl_Position = vertex_attrib; - gl_Position.z = 1.0; -} - -/* clang-format off */ -[fragment] - -#define TWO_PI 6.283185307179586476925286766559 - -#ifdef SSAO_QUALITY_HIGH -#define NUM_SAMPLES (16) -#endif - -#ifdef SSAO_QUALITY_LOW -#define NUM_SAMPLES (8) -#endif - -#if !defined(SSAO_QUALITY_LOW) && !defined(SSAO_QUALITY_HIGH) -#define NUM_SAMPLES (12) -#endif - -// If using depth mip levels, the log of the maximum pixel offset before we need to switch to a lower -// miplevel to maintain reasonable spatial locality in the cache -// If this number is too small (< 3), too many taps will land in the same pixel, and we'll get bad variance that manifests as flashing. -// If it is too high (> 5), we'll get bad performance because we're not using the MIP levels effectively -#define LOG_MAX_OFFSET (3) - -// This must be less than or equal to the MAX_MIP_LEVEL defined in SSAO.cpp -#define MAX_MIP_LEVEL (4) - -// This is the number of turns around the circle that the spiral pattern makes. This should be prime to prevent -// taps from lining up. This particular choice was tuned for NUM_SAMPLES == 9 - -const int ROTATIONS[] = int[]( - 1, 1, 2, 3, 2, 5, 2, 3, 2, - 3, 3, 5, 5, 3, 4, 7, 5, 5, 7, - 9, 8, 5, 5, 7, 7, 7, 8, 5, 8, - 11, 12, 7, 10, 13, 8, 11, 8, 7, 14, - 11, 11, 13, 12, 13, 19, 17, 13, 11, 18, - 19, 11, 11, 14, 17, 21, 15, 16, 17, 18, - 13, 17, 11, 17, 19, 18, 25, 18, 19, 19, - 29, 21, 19, 27, 31, 29, 21, 18, 17, 29, - 31, 31, 23, 18, 25, 26, 25, 23, 19, 34, - 19, 27, 21, 25, 39, 29, 17, 21, 27); -/* clang-format on */ - -//#define NUM_SPIRAL_TURNS (7) -const int NUM_SPIRAL_TURNS = ROTATIONS[NUM_SAMPLES - 1]; - -uniform sampler2D source_depth; //texunit:0 -uniform highp usampler2D source_depth_mipmaps; //texunit:1 -uniform sampler2D source_normal; //texunit:2 - -uniform ivec2 screen_size; -uniform float camera_z_far; -uniform float camera_z_near; - -uniform float intensity_div_r6; -uniform float radius; - -#ifdef ENABLE_RADIUS2 -uniform float intensity_div_r62; -uniform float radius2; -#endif - -uniform float bias; -uniform float proj_scale; - -layout(location = 0) out float visibility; - -uniform vec4 proj_info; - -vec3 reconstructCSPosition(vec2 S, float z) { -#ifdef USE_ORTHOGONAL_PROJECTION - return vec3((S.xy * proj_info.xy + proj_info.zw), z); -#else - return vec3((S.xy * proj_info.xy + proj_info.zw) * z, z); - -#endif -} - -vec3 getPosition(ivec2 ssP) { - vec3 P; - P.z = texelFetch(source_depth, ssP, 0).r; - - P.z = P.z * 2.0 - 1.0; -#ifdef USE_ORTHOGONAL_PROJECTION - P.z = ((P.z + (camera_z_far + camera_z_near) / (camera_z_far - camera_z_near)) * (camera_z_far - camera_z_near)) / 2.0; -#else - P.z = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - P.z * (camera_z_far - camera_z_near)); -#endif - P.z = -P.z; - - // Offset to pixel center - P = reconstructCSPosition(vec2(ssP) + vec2(0.5), P.z); - return P; -} - -/** Reconstructs screen-space unit normal from screen-space position */ -vec3 reconstructCSFaceNormal(vec3 C) { - return normalize(cross(dFdy(C), dFdx(C))); -} - -/** Returns a unit vector and a screen-space radius for the tap on a unit disk (the caller should scale by the actual disk radius) */ -vec2 tapLocation(int sampleNumber, float spinAngle, out float ssR) { - // Radius relative to ssR - float alpha = (float(sampleNumber) + 0.5) * (1.0 / float(NUM_SAMPLES)); - float angle = alpha * (float(NUM_SPIRAL_TURNS) * 6.28) + spinAngle; - - ssR = alpha; - return vec2(cos(angle), sin(angle)); -} - -/** Read the camera-space position of the point at screen-space pixel ssP + unitOffset * ssR. Assumes length(unitOffset) == 1 */ -vec3 getOffsetPosition(ivec2 ssC, vec2 unitOffset, float ssR) { - // Derivation: - // mipLevel = floor(log(ssR / MAX_OFFSET)); - int mipLevel = clamp(int(floor(log2(ssR))) - LOG_MAX_OFFSET, 0, MAX_MIP_LEVEL); - - ivec2 ssP = ivec2(ssR * unitOffset) + ssC; - - vec3 P; - - // We need to divide by 2^mipLevel to read the appropriately scaled coordinate from a MIP-map. - // Manually clamp to the texture size because texelFetch bypasses the texture unit - ivec2 mipP = clamp(ssP >> mipLevel, ivec2(0), (screen_size >> mipLevel) - ivec2(1)); - - if (mipLevel < 1) { - //read from depth buffer - P.z = texelFetch(source_depth, mipP, 0).r; - P.z = P.z * 2.0 - 1.0; -#ifdef USE_ORTHOGONAL_PROJECTION - P.z = ((P.z + (camera_z_far + camera_z_near) / (camera_z_far - camera_z_near)) * (camera_z_far - camera_z_near)) / 2.0; -#else - P.z = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - P.z * (camera_z_far - camera_z_near)); -#endif - P.z = -P.z; - - } else { - //read from mipmaps - uint d = texelFetch(source_depth_mipmaps, mipP, mipLevel - 1).r; - P.z = -(float(d) / 65535.0) * camera_z_far; - } - - // Offset to pixel center - P = reconstructCSPosition(vec2(ssP) + vec2(0.5), P.z); - - return P; -} - -/** Compute the occlusion due to sample with index \a i about the pixel at \a ssC that corresponds - to camera-space point \a C with unit normal \a n_C, using maximum screen-space sampling radius \a ssDiskRadius - - Note that units of H() in the HPG12 paper are meters, not - unitless. The whole falloff/sampling function is therefore - unitless. In this implementation, we factor out (9 / radius). - - Four versions of the falloff function are implemented below -*/ -float sampleAO(in ivec2 ssC, in vec3 C, in vec3 n_C, in float ssDiskRadius, in float p_radius, in int tapIndex, in float randomPatternRotationAngle) { - // Offset on the unit disk, spun for this pixel - float ssR; - vec2 unitOffset = tapLocation(tapIndex, randomPatternRotationAngle, ssR); - ssR *= ssDiskRadius; - - // The occluding point in camera space - vec3 Q = getOffsetPosition(ssC, unitOffset, ssR); - - vec3 v = Q - C; - - float vv = dot(v, v); - float vn = dot(v, n_C); - - const float epsilon = 0.01; - float radius2 = p_radius * p_radius; - - // A: From the HPG12 paper - // Note large epsilon to avoid overdarkening within cracks - //return float(vv < radius2) * max((vn - bias) / (epsilon + vv), 0.0) * radius2 * 0.6; - - // B: Smoother transition to zero (lowers contrast, smoothing out corners). [Recommended] - float f = max(radius2 - vv, 0.0); - return f * f * f * max((vn - bias) / (epsilon + vv), 0.0); - - // C: Medium contrast (which looks better at high radii), no division. Note that the - // contribution still falls off with radius^2, but we've adjusted the rate in a way that is - // more computationally efficient and happens to be aesthetically pleasing. - // return 4.0 * max(1.0 - vv * invRadius2, 0.0) * max(vn - bias, 0.0); - - // D: Low contrast, no division operation - // return 2.0 * float(vv < radius * radius) * max(vn - bias, 0.0); -} - -void main() { - // Pixel being shaded - ivec2 ssC = ivec2(gl_FragCoord.xy); - - // World space point being shaded - vec3 C = getPosition(ssC); - - /* - if (C.z <= -camera_z_far * 0.999) { - // We're on the skybox - visibility=1.0; - return; - } - */ - - //visibility = -C.z / camera_z_far; - //return; -#if 0 - vec3 n_C = texelFetch(source_normal, ssC, 0).rgb * 2.0 - 1.0; -#else - vec3 n_C = reconstructCSFaceNormal(C); - n_C = -n_C; -#endif - - // Hash function used in the HPG12 AlchemyAO paper - float randomPatternRotationAngle = mod(float((3 * ssC.x ^ ssC.y + ssC.x * ssC.y) * 10), TWO_PI); - - // Reconstruct normals from positions. These will lead to 1-pixel black lines - // at depth discontinuities, however the blur will wipe those out so they are not visible - // in the final image. - - // Choose the screen-space sample radius - // proportional to the projected area of the sphere -#ifdef USE_ORTHOGONAL_PROJECTION - float ssDiskRadius = -proj_scale * radius; -#else - float ssDiskRadius = -proj_scale * radius / C.z; -#endif - float sum = 0.0; - for (int i = 0; i < NUM_SAMPLES; ++i) { - sum += sampleAO(ssC, C, n_C, ssDiskRadius, radius, i, randomPatternRotationAngle); - } - - float A = max(0.0, 1.0 - sum * intensity_div_r6 * (5.0 / float(NUM_SAMPLES))); - -#ifdef ENABLE_RADIUS2 - - //go again for radius2 - randomPatternRotationAngle = mod(float((5 * ssC.x ^ ssC.y + ssC.x * ssC.y) * 11), TWO_PI); - - // Reconstruct normals from positions. These will lead to 1-pixel black lines - // at depth discontinuities, however the blur will wipe those out so they are not visible - // in the final image. - - // Choose the screen-space sample radius - // proportional to the projected area of the sphere - ssDiskRadius = -proj_scale * radius2 / C.z; - - sum = 0.0; - for (int i = 0; i < NUM_SAMPLES; ++i) { - sum += sampleAO(ssC, C, n_C, ssDiskRadius, radius2, i, randomPatternRotationAngle); - } - - A = min(A, max(0.0, 1.0 - sum * intensity_div_r62 * (5.0 / float(NUM_SAMPLES)))); -#endif - // Bilateral box-filter over a quad for free, respecting depth edges - // (the difference that this makes is subtle) - if (abs(dFdx(C.z)) < 0.02) { - A -= dFdx(A) * (float(ssC.x & 1) - 0.5); - } - if (abs(dFdy(C.z)) < 0.02) { - A -= dFdy(A) * (float(ssC.y & 1) - 0.5); - } - - visibility = A; -} diff --git a/drivers/gles3/shaders/ssao_blur.glsl b/drivers/gles3/shaders/ssao_blur.glsl deleted file mode 100644 index c49ea1e957..0000000000 --- a/drivers/gles3/shaders/ssao_blur.glsl +++ /dev/null @@ -1,119 +0,0 @@ -/* clang-format off */ -[vertex] - -layout(location = 0) in highp vec4 vertex_attrib; -/* clang-format on */ - -void main() { - - gl_Position = vertex_attrib; - gl_Position.z = 1.0; -} - -/* clang-format off */ -[fragment] - -uniform sampler2D source_ssao; //texunit:0 -/* clang-format on */ -uniform sampler2D source_depth; //texunit:1 -uniform sampler2D source_normal; //texunit:3 - -layout(location = 0) out float visibility; - -////////////////////////////////////////////////////////////////////////////////////////////// -// Tunable Parameters: - -/** Increase to make depth edges crisper. Decrease to reduce flicker. */ -uniform float edge_sharpness; - -/** Step in 2-pixel intervals since we already blurred against neighbors in the - first AO pass. This constant can be increased while R decreases to improve - performance at the expense of some dithering artifacts. - - Morgan found that a scale of 3 left a 1-pixel checkerboard grid that was - unobjectionable after shading was applied but eliminated most temporal incoherence - from using small numbers of sample taps. - */ - -uniform int filter_scale; - -/** Filter radius in pixels. This will be multiplied by SCALE. */ -#define R (4) - -////////////////////////////////////////////////////////////////////////////////////////////// - -// Gaussian coefficients -const float gaussian[R + 1] = - //float[](0.356642, 0.239400, 0.072410, 0.009869); - //float[](0.398943, 0.241971, 0.053991, 0.004432, 0.000134); // stddev = 1.0 - float[](0.153170, 0.144893, 0.122649, 0.092902, 0.062970); // stddev = 2.0 -//float[](0.111220, 0.107798, 0.098151, 0.083953, 0.067458, 0.050920, 0.036108); // stddev = 3.0 - -/** (1, 0) or (0, 1) */ -uniform ivec2 axis; - -uniform float camera_z_far; -uniform float camera_z_near; - -uniform ivec2 screen_size; - -void main() { - - ivec2 ssC = ivec2(gl_FragCoord.xy); - - float depth = texelFetch(source_depth, ssC, 0).r; - //vec3 normal = texelFetch(source_normal, ssC, 0).rgb * 2.0 - 1.0; - - depth = depth * 2.0 - 1.0; - depth = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - depth * (camera_z_far - camera_z_near)); - - float depth_divide = 1.0 / camera_z_far; - - //depth *= depth_divide; - - /* - if (depth > camera_z_far * 0.999) { - discard; //skybox - } - */ - - float sum = texelFetch(source_ssao, ssC, 0).r; - - // Base weight for depth falloff. Increase this for more blurriness, - // decrease it for better edge discrimination - float BASE = gaussian[0]; - float totalWeight = BASE; - sum *= totalWeight; - - ivec2 clamp_limit = screen_size - ivec2(1); - - for (int r = -R; r <= R; ++r) { - // We already handled the zero case above. This loop should be unrolled and the static branch optimized out, - // so the IF statement has no runtime cost - if (r != 0) { - - ivec2 ppos = ssC + axis * (r * filter_scale); - float value = texelFetch(source_ssao, clamp(ppos, ivec2(0), clamp_limit), 0).r; - ivec2 rpos = clamp(ppos, ivec2(0), clamp_limit); - float temp_depth = texelFetch(source_depth, rpos, 0).r; - //vec3 temp_normal = texelFetch(source_normal, rpos, 0).rgb * 2.0 - 1.0; - - temp_depth = temp_depth * 2.0 - 1.0; - temp_depth = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - temp_depth * (camera_z_far - camera_z_near)); - //temp_depth *= depth_divide; - - // spatial domain: offset gaussian tap - float weight = 0.3 + gaussian[abs(r)]; - //weight *= max(0.0, dot(temp_normal, normal)); - - // range domain (the "bilateral" weight). As depth difference increases, decrease weight. - weight *= max(0.0, 1.0 - edge_sharpness * abs(temp_depth - depth)); - - sum += value * weight; - totalWeight += weight; - } - } - - const float epsilon = 0.0001; - visibility = sum / (totalWeight + epsilon); -} diff --git a/drivers/gles3/shaders/ssao_minify.glsl b/drivers/gles3/shaders/ssao_minify.glsl deleted file mode 100644 index 1696648dae..0000000000 --- a/drivers/gles3/shaders/ssao_minify.glsl +++ /dev/null @@ -1,56 +0,0 @@ -/* clang-format off */ -[vertex] - -layout(location = 0) in highp vec4 vertex_attrib; -/* clang-format on */ - -void main() { - - gl_Position = vertex_attrib; -} - -/* clang-format off */ -[fragment] - -#ifdef MINIFY_START - -#define SDEPTH_TYPE highp sampler2D -uniform float camera_z_far; -/* clang-format on */ -uniform float camera_z_near; - -#else - -#define SDEPTH_TYPE mediump usampler2D - -#endif - -uniform SDEPTH_TYPE source_depth; //texunit:0 - -uniform ivec2 from_size; -uniform int source_mipmap; - -layout(location = 0) out mediump uint depth; - -void main() { - - ivec2 ssP = ivec2(gl_FragCoord.xy); - - // Rotated grid subsampling to avoid XY directional bias or Z precision bias while downsampling. - // On DX9, the bit-and can be implemented with floating-point modulo - -#ifdef MINIFY_START - float fdepth = texelFetch(source_depth, clamp(ssP * 2 + ivec2(ssP.y & 1, ssP.x & 1), ivec2(0), from_size - ivec2(1)), source_mipmap).r; - fdepth = fdepth * 2.0 - 1.0; -#ifdef USE_ORTHOGONAL_PROJECTION - fdepth = ((fdepth + (camera_z_far + camera_z_near) / (camera_z_far - camera_z_near)) * (camera_z_far - camera_z_near)) / 2.0; -#else - fdepth = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - fdepth * (camera_z_far - camera_z_near)); -#endif - fdepth /= camera_z_far; - depth = uint(clamp(fdepth * 65535.0, 0.0, 65535.0)); - -#else - depth = texelFetch(source_depth, clamp(ssP * 2 + ivec2(ssP.y & 1, ssP.x & 1), ivec2(0), from_size - ivec2(1)), source_mipmap).r; -#endif -} diff --git a/drivers/gles3/shaders/subsurf_scattering.glsl b/drivers/gles3/shaders/subsurf_scattering.glsl deleted file mode 100644 index f40fb3a244..0000000000 --- a/drivers/gles3/shaders/subsurf_scattering.glsl +++ /dev/null @@ -1,174 +0,0 @@ -/* clang-format off */ -[vertex] - -layout(location = 0) in highp vec4 vertex_attrib; -/* clang-format on */ -layout(location = 4) in vec2 uv_in; - -out vec2 uv_interp; - -void main() { - - uv_interp = uv_in; - gl_Position = vertex_attrib; -} - -/* clang-format off */ -[fragment] - -//#define QUALIFIER uniform // some guy on the interweb says it may be faster with this -#define QUALIFIER const - -#ifdef USE_25_SAMPLES -const int kernel_size = 25; -/* clang-format on */ -QUALIFIER vec2 kernel[25] = vec2[]( - vec2(0.530605, 0.0), - vec2(0.000973794, -3.0), - vec2(0.00333804, -2.52083), - vec2(0.00500364, -2.08333), - vec2(0.00700976, -1.6875), - vec2(0.0094389, -1.33333), - vec2(0.0128496, -1.02083), - vec2(0.017924, -0.75), - vec2(0.0263642, -0.520833), - vec2(0.0410172, -0.333333), - vec2(0.0493588, -0.1875), - vec2(0.0402784, -0.0833333), - vec2(0.0211412, -0.0208333), - vec2(0.0211412, 0.0208333), - vec2(0.0402784, 0.0833333), - vec2(0.0493588, 0.1875), - vec2(0.0410172, 0.333333), - vec2(0.0263642, 0.520833), - vec2(0.017924, 0.75), - vec2(0.0128496, 1.02083), - vec2(0.0094389, 1.33333), - vec2(0.00700976, 1.6875), - vec2(0.00500364, 2.08333), - vec2(0.00333804, 2.52083), - vec2(0.000973794, 3.0)); -#endif //USE_25_SAMPLES - -#ifdef USE_17_SAMPLES -const int kernel_size = 17; -QUALIFIER vec2 kernel[17] = vec2[]( - vec2(0.536343, 0.0), - vec2(0.00317394, -2.0), - vec2(0.0100386, -1.53125), - vec2(0.0144609, -1.125), - vec2(0.0216301, -0.78125), - vec2(0.0347317, -0.5), - vec2(0.0571056, -0.28125), - vec2(0.0582416, -0.125), - vec2(0.0324462, -0.03125), - vec2(0.0324462, 0.03125), - vec2(0.0582416, 0.125), - vec2(0.0571056, 0.28125), - vec2(0.0347317, 0.5), - vec2(0.0216301, 0.78125), - vec2(0.0144609, 1.125), - vec2(0.0100386, 1.53125), - vec2(0.00317394, 2.0)); -#endif //USE_17_SAMPLES - -#ifdef USE_11_SAMPLES -const int kernel_size = 11; -QUALIFIER vec2 kernel[11] = vec2[]( - vec2(0.560479, 0.0), - vec2(0.00471691, -2.0), - vec2(0.0192831, -1.28), - vec2(0.03639, -0.72), - vec2(0.0821904, -0.32), - vec2(0.0771802, -0.08), - vec2(0.0771802, 0.08), - vec2(0.0821904, 0.32), - vec2(0.03639, 0.72), - vec2(0.0192831, 1.28), - vec2(0.00471691, 2.0)); -#endif //USE_11_SAMPLES - -uniform float max_radius; -uniform float camera_z_far; -uniform float camera_z_near; -uniform float unit_size; -uniform vec2 dir; -in vec2 uv_interp; - -uniform sampler2D source_diffuse; //texunit:0 -uniform sampler2D source_sss; //texunit:1 -uniform sampler2D source_depth; //texunit:2 - -layout(location = 0) out vec4 frag_color; - -void main() { - - float strength = texture(source_sss, uv_interp).r; - strength *= strength; //stored as sqrt - - // Fetch color of current pixel: - vec4 base_color = texture(source_diffuse, uv_interp); - - if (strength > 0.0) { - - // Fetch linear depth of current pixel: - float depth = texture(source_depth, uv_interp).r * 2.0 - 1.0; -#ifdef USE_ORTHOGONAL_PROJECTION - depth = ((depth + (camera_z_far + camera_z_near) / (camera_z_far - camera_z_near)) * (camera_z_far - camera_z_near)) / 2.0; - float scale = unit_size; //remember depth is negative by default in OpenGL -#else - depth = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - depth * (camera_z_far - camera_z_near)); - float scale = unit_size / depth; //remember depth is negative by default in OpenGL -#endif - - // Calculate the final step to fetch the surrounding pixels: - vec2 step = max_radius * scale * dir; - step *= strength; // Modulate it using the alpha channel. - step *= 1.0 / 3.0; // Divide by 3 as the kernels range from -3 to 3. - - // Accumulate the center sample: - vec3 color_accum = base_color.rgb; - color_accum *= kernel[0].x; -#ifdef ENABLE_STRENGTH_WEIGHTING - float color_weight = kernel[0].x; -#endif - - // Accumulate the other samples: - for (int i = 1; i < kernel_size; i++) { - // Fetch color and depth for current sample: - vec2 offset = uv_interp + kernel[i].y * step; - vec3 color = texture(source_diffuse, offset).rgb; - -#ifdef ENABLE_FOLLOW_SURFACE - // If the difference in depth is huge, we lerp color back to "colorM": - float depth_cmp = texture(source_depth, offset).r * 2.0 - 1.0; - -#ifdef USE_ORTHOGONAL_PROJECTION - depth_cmp = ((depth_cmp + (camera_z_far + camera_z_near) / (camera_z_far - camera_z_near)) * (camera_z_far - camera_z_near)) / 2.0; -#else - depth_cmp = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - depth_cmp * (camera_z_far - camera_z_near)); -#endif - - float s = clamp(300.0f * scale * max_radius * abs(depth - depth_cmp), 0.0, 1.0); - color = mix(color, base_color.rgb, s); -#endif - - // Accumulate: - color *= kernel[i].x; - -#ifdef ENABLE_STRENGTH_WEIGHTING - float color_s = texture(source_sss, offset).r; - color_weight += color_s * kernel[i].x; - color *= color_s; -#endif - color_accum += color; - } - -#ifdef ENABLE_STRENGTH_WEIGHTING - color_accum /= color_weight; -#endif - frag_color = vec4(color_accum, base_color.a); //keep alpha (used for SSAO) - } else { - frag_color = base_color; - } -} diff --git a/drivers/gles3/shaders/tonemap.glsl b/drivers/gles3/shaders/tonemap.glsl deleted file mode 100644 index f1fe1742eb..0000000000 --- a/drivers/gles3/shaders/tonemap.glsl +++ /dev/null @@ -1,309 +0,0 @@ -/* clang-format off */ -[vertex] - -layout(location = 0) in highp vec4 vertex_attrib; -/* clang-format on */ -layout(location = 4) in vec2 uv_in; - -out vec2 uv_interp; - -void main() { - gl_Position = vertex_attrib; - - uv_interp = uv_in; - -#ifdef V_FLIP - uv_interp.y = 1.0f - uv_interp.y; -#endif -} - -/* clang-format off */ -[fragment] - -#if !defined(GLES_OVER_GL) -precision mediump float; -#endif -/* clang-format on */ - -in vec2 uv_interp; - -uniform highp sampler2D source; //texunit:0 - -uniform float exposure; -uniform float white; - -#ifdef USE_AUTO_EXPOSURE -uniform highp sampler2D source_auto_exposure; //texunit:1 -uniform highp float auto_exposure_grey; -#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) -#define USING_GLOW // only use glow when at least one glow level is selected - -uniform highp sampler2D source_glow; //texunit:2 -uniform highp float glow_intensity; -#endif - -#ifdef USE_BCS -uniform vec3 bcs; -#endif - -#ifdef USE_COLOR_CORRECTION -uniform sampler2D color_correction; //texunit:3 -#endif - -layout(location = 0) out vec4 frag_color; - -#ifdef USE_GLOW_FILTER_BICUBIC -// w0, w1, w2, and w3 are the four cubic B-spline basis functions -float w0(float a) { - return (1.0f / 6.0f) * (a * (a * (-a + 3.0f) - 3.0f) + 1.0f); -} - -float w1(float a) { - return (1.0f / 6.0f) * (a * a * (3.0f * a - 6.0f) + 4.0f); -} - -float w2(float a) { - return (1.0f / 6.0f) * (a * (a * (-3.0f * a + 3.0f) + 3.0f) + 1.0f); -} - -float w3(float a) { - return (1.0f / 6.0f) * (a * a * a); -} - -// g0 and g1 are the two amplitude functions -float g0(float a) { - return w0(a) + w1(a); -} - -float g1(float a) { - return w2(a) + w3(a); -} - -// h0 and h1 are the two offset functions -float h0(float a) { - return -1.0f + w1(a) / (w0(a) + w1(a)); -} - -float h1(float a) { - return 1.0f + w3(a) / (w2(a) + w3(a)); -} - -uniform ivec2 glow_texture_size; - -vec4 texture2D_bicubic(sampler2D tex, vec2 uv, int p_lod) { - float lod = float(p_lod); - vec2 tex_size = vec2(glow_texture_size >> p_lod); - vec2 pixel_size = vec2(1.0f) / tex_size; - - uv = uv * tex_size + vec2(0.5f); - - vec2 iuv = floor(uv); - vec2 fuv = fract(uv); - - float g0x = g0(fuv.x); - float g1x = g1(fuv.x); - float h0x = h0(fuv.x); - float h1x = h1(fuv.x); - float h0y = h0(fuv.y); - float h1y = h1(fuv.y); - - vec2 p0 = (vec2(iuv.x + h0x, iuv.y + h0y) - vec2(0.5f)) * pixel_size; - vec2 p1 = (vec2(iuv.x + h1x, iuv.y + h0y) - vec2(0.5f)) * pixel_size; - vec2 p2 = (vec2(iuv.x + h0x, iuv.y + h1y) - vec2(0.5f)) * pixel_size; - vec2 p3 = (vec2(iuv.x + h1x, iuv.y + h1y) - vec2(0.5f)) * pixel_size; - - return (g0(fuv.y) * (g0x * textureLod(tex, p0, lod) + g1x * textureLod(tex, p1, lod))) + - (g1(fuv.y) * (g0x * textureLod(tex, p2, lod) + g1x * textureLod(tex, p3, lod))); -} - -#define GLOW_TEXTURE_SAMPLE(m_tex, m_uv, m_lod) texture2D_bicubic(m_tex, m_uv, m_lod) -#else -#define GLOW_TEXTURE_SAMPLE(m_tex, m_uv, m_lod) textureLod(m_tex, m_uv, float(m_lod)) -#endif - -vec3 tonemap_filmic(vec3 color, float white) { - // exposure bias: input scale (color *= bias, white *= bias) to make the brightness consistent with other tonemappers - // also useful to scale the input to the range that the tonemapper is designed for (some require very high input values) - // has no effect on the curve's general shape or visual properties - const float exposure_bias = 2.0f; - const float A = 0.22f * exposure_bias * exposure_bias; // bias baked into constants for performance - const float B = 0.30f * exposure_bias; - const float C = 0.10f; - const float D = 0.20f; - const float E = 0.01f; - const float F = 0.30f; - - vec3 color_tonemapped = ((color * (A * color + C * B) + D * E) / (color * (A * color + B) + D * F)) - E / F; - float white_tonemapped = ((white * (A * white + C * B) + D * E) / (white * (A * white + B) + D * F)) - E / F; - - return clamp(color_tonemapped / white_tonemapped, vec3(0.0f), vec3(1.0f)); -} - -vec3 tonemap_aces(vec3 color, float white) { - const float exposure_bias = 0.85f; - const float A = 2.51f * exposure_bias * exposure_bias; - const float B = 0.03f * exposure_bias; - const float C = 2.43f * exposure_bias * exposure_bias; - const float D = 0.59f * exposure_bias; - const float E = 0.14f; - - vec3 color_tonemapped = (color * (A * color + B)) / (color * (C * color + D) + E); - float white_tonemapped = (white * (A * white + B)) / (white * (C * white + D) + E); - - return clamp(color_tonemapped / white_tonemapped, vec3(0.0f), vec3(1.0f)); -} - -vec3 tonemap_reinhard(vec3 color, float white) { - return clamp((white * color + color) / (color * white + white), vec3(0.0f), vec3(1.0f)); -} - -vec3 linear_to_srgb(vec3 color) { // convert linear rgb to srgb, assumes clamped input in range [0;1] - const vec3 a = vec3(0.055f); - return mix((vec3(1.0f) + a) * pow(color.rgb, vec3(1.0f / 2.4f)) - a, 12.92f * color.rgb, lessThan(color.rgb, vec3(0.0031308f))); -} - -// inputs are LINEAR, If Linear tonemapping is selected no transform is performed else outputs are clamped [0, 1] color -vec3 apply_tonemapping(vec3 color, float white) { -#ifdef USE_REINHARD_TONEMAPPER - return tonemap_reinhard(color, white); -#endif - -#ifdef USE_FILMIC_TONEMAPPER - return tonemap_filmic(color, white); -#endif - -#ifdef USE_ACES_TONEMAPPER - return tonemap_aces(color, white); -#endif - - return color; // no other selected -> linear: no color transform applied -} - -vec3 gather_glow(sampler2D tex, vec2 uv) { // sample all selected glow levels - vec3 glow = vec3(0.0f); - -#ifdef USE_GLOW_LEVEL1 - glow += GLOW_TEXTURE_SAMPLE(tex, uv, 1).rgb; -#endif - -#ifdef USE_GLOW_LEVEL2 - glow += GLOW_TEXTURE_SAMPLE(tex, uv, 2).rgb; -#endif - -#ifdef USE_GLOW_LEVEL3 - glow += GLOW_TEXTURE_SAMPLE(tex, uv, 3).rgb; -#endif - -#ifdef USE_GLOW_LEVEL4 - glow += GLOW_TEXTURE_SAMPLE(tex, uv, 4).rgb; -#endif - -#ifdef USE_GLOW_LEVEL5 - glow += GLOW_TEXTURE_SAMPLE(tex, uv, 5).rgb; -#endif - -#ifdef USE_GLOW_LEVEL6 - glow += GLOW_TEXTURE_SAMPLE(tex, uv, 6).rgb; -#endif - -#ifdef USE_GLOW_LEVEL7 - glow += GLOW_TEXTURE_SAMPLE(tex, uv, 7).rgb; -#endif - - return glow; -} - -vec3 apply_glow(vec3 color, vec3 glow) { // apply glow using the selected blending mode -#ifdef USE_GLOW_REPLACE - color = glow; -#endif - -#ifdef USE_GLOW_SCREEN - //need color clamping - color = clamp(color, vec3(0.0f), vec3(1.0f)); - color = max((color + glow) - (color * glow), vec3(0.0)); -#endif - -#ifdef USE_GLOW_SOFTLIGHT - //need color clamping - color = clamp(color, vec3(0.0f), vec3(1.0)); - glow = glow * vec3(0.5f) + vec3(0.5f); - - color.r = (glow.r <= 0.5f) ? (color.r - (1.0f - 2.0f * glow.r) * color.r * (1.0f - color.r)) : (((glow.r > 0.5f) && (color.r <= 0.25f)) ? (color.r + (2.0f * glow.r - 1.0f) * (4.0f * color.r * (4.0f * color.r + 1.0f) * (color.r - 1.0f) + 7.0f * color.r)) : (color.r + (2.0f * glow.r - 1.0f) * (sqrt(color.r) - color.r))); - color.g = (glow.g <= 0.5f) ? (color.g - (1.0f - 2.0f * glow.g) * color.g * (1.0f - color.g)) : (((glow.g > 0.5f) && (color.g <= 0.25f)) ? (color.g + (2.0f * glow.g - 1.0f) * (4.0f * color.g * (4.0f * color.g + 1.0f) * (color.g - 1.0f) + 7.0f * color.g)) : (color.g + (2.0f * glow.g - 1.0f) * (sqrt(color.g) - color.g))); - color.b = (glow.b <= 0.5f) ? (color.b - (1.0f - 2.0f * glow.b) * color.b * (1.0f - color.b)) : (((glow.b > 0.5f) && (color.b <= 0.25f)) ? (color.b + (2.0f * glow.b - 1.0f) * (4.0f * color.b * (4.0f * color.b + 1.0f) * (color.b - 1.0f) + 7.0f * color.b)) : (color.b + (2.0f * glow.b - 1.0f) * (sqrt(color.b) - color.b))); -#endif - -#if !defined(USE_GLOW_SCREEN) && !defined(USE_GLOW_SOFTLIGHT) && !defined(USE_GLOW_REPLACE) // no other selected -> additive - color += glow; -#endif - - return color; -} - -vec3 apply_bcs(vec3 color, vec3 bcs) { - color = mix(vec3(0.0f), color, bcs.x); - color = mix(vec3(0.5f), color, bcs.y); - color = mix(vec3(dot(vec3(1.0f), color) * 0.33333f), color, bcs.z); - - return color; -} - -vec3 apply_color_correction(vec3 color, sampler2D correction_tex) { - color.r = texture(correction_tex, vec2(color.r, 0.0f)).r; - color.g = texture(correction_tex, vec2(color.g, 0.0f)).g; - color.b = texture(correction_tex, vec2(color.b, 0.0f)).b; - - return color; -} - -void main() { - vec3 color = textureLod(source, uv_interp, 0.0f).rgb; - - // Exposure - -#ifdef USE_AUTO_EXPOSURE - color /= texelFetch(source_auto_exposure, ivec2(0, 0), 0).r / auto_exposure_grey; -#endif - - color *= exposure; - - // Early Tonemap & SRGB Conversion; note that Linear tonemapping does not clamp to [0, 1]; some operations below expect a [0, 1] range and will clamp - - color = apply_tonemapping(color, white); - -#ifdef KEEP_3D_LINEAR - // leave color as is (-> don't convert to SRGB) -#else - //need color clamping - color = clamp(color, vec3(0.0f), vec3(1.0f)); - color = linear_to_srgb(color); // regular linear -> SRGB conversion (needs clamped values) -#endif - - // Glow - -#ifdef USING_GLOW - vec3 glow = gather_glow(source_glow, uv_interp) * glow_intensity; - - // high dynamic range -> SRGB - glow = apply_tonemapping(glow, white); - glow = clamp(glow, vec3(0.0f), vec3(1.0f)); - glow = linear_to_srgb(glow); - - color = apply_glow(color, glow); -#endif - - // Additional effects - -#ifdef USE_BCS - color = apply_bcs(color, bcs); -#endif - -#ifdef USE_COLOR_CORRECTION - color = apply_color_correction(color, color_correction); -#endif - - frag_color = vec4(color, 1.0f); -} diff --git a/drivers/png/png_driver_common.cpp b/drivers/png/png_driver_common.cpp index f4dbf135bb..750d00eb59 100644 --- a/drivers/png/png_driver_common.cpp +++ b/drivers/png/png_driver_common.cpp @@ -114,6 +114,7 @@ Error png_to_image(const uint8_t *p_source, size_t p_size, Ref<Image> p_image) { ERR_FAIL_COND_V_MSG(check_error(png_img), ERR_FILE_CORRUPT, png_img.message); ERR_FAIL_COND_V(!success, ERR_FILE_CORRUPT); + //print_line("png width: "+itos(png_img.width)+" height: "+itos(png_img.height)); p_image->create(png_img.width, png_img.height, 0, dest_format, buffer); return OK; diff --git a/drivers/png/resource_saver_png.cpp b/drivers/png/resource_saver_png.cpp index b15a84d3b9..566bfbcc1d 100644 --- a/drivers/png/resource_saver_png.cpp +++ b/drivers/png/resource_saver_png.cpp @@ -71,6 +71,14 @@ Error ResourceSaverPNG::save_image(const String &p_path, const Ref<Image> &p_img return OK; } +PoolVector<uint8_t> ResourceSaverPNG::save_image_to_buffer(const Ref<Image> &p_img) { + + PoolVector<uint8_t> buffer; + Error err = PNGDriverCommon::image_to_png(p_img, buffer); + ERR_FAIL_COND_V_MSG(err, PoolVector<uint8_t>(), "Can't convert image to PNG."); + return buffer; +} + bool ResourceSaverPNG::recognize(const RES &p_resource) const { return (p_resource.is_valid() && p_resource->is_class("ImageTexture")); @@ -86,4 +94,5 @@ void ResourceSaverPNG::get_recognized_extensions(const RES &p_resource, List<Str ResourceSaverPNG::ResourceSaverPNG() { Image::save_png_func = &save_image; + Image::save_png_buffer_func = &save_image_to_buffer; }; diff --git a/drivers/png/resource_saver_png.h b/drivers/png/resource_saver_png.h index 6eb1db2004..2cac20991a 100644 --- a/drivers/png/resource_saver_png.h +++ b/drivers/png/resource_saver_png.h @@ -37,6 +37,7 @@ class ResourceSaverPNG : public ResourceFormatSaver { public: static Error save_image(const String &p_path, const Ref<Image> &p_img); + static PoolVector<uint8_t> save_image_to_buffer(const Ref<Image> &p_img); virtual Error save(const String &p_path, const RES &p_resource, uint32_t p_flags = 0); virtual bool recognize(const RES &p_resource) const; diff --git a/drivers/pulseaudio/audio_driver_pulseaudio.cpp b/drivers/pulseaudio/audio_driver_pulseaudio.cpp index 524f0363a1..df9303fbec 100644 --- a/drivers/pulseaudio/audio_driver_pulseaudio.cpp +++ b/drivers/pulseaudio/audio_driver_pulseaudio.cpp @@ -176,7 +176,7 @@ Error AudioDriverPulseAudio::init_device() { break; default: - WARN_PRINTS("PulseAudio: Unsupported number of channels: " + itos(pa_map.channels)); + WARN_PRINT("PulseAudio: Unsupported number of channels: " + itos(pa_map.channels)); pa_channel_map_init_stereo(&pa_map); channels = 2; break; @@ -204,7 +204,7 @@ Error AudioDriverPulseAudio::init_device() { pa_str = pa_stream_new(pa_ctx, "Sound", &spec, &pa_map); if (pa_str == NULL) { - ERR_PRINTS("PulseAudio: pa_stream_new error: " + String(pa_strerror(pa_context_errno(pa_ctx)))); + ERR_PRINT("PulseAudio: pa_stream_new error: " + String(pa_strerror(pa_context_errno(pa_ctx)))); ERR_FAIL_V(ERR_CANT_OPEN); } @@ -388,7 +388,7 @@ void AudioDriverPulseAudio::thread_func(void *p_udata) { const void *ptr = ad->samples_out.ptr(); ret = pa_stream_write(ad->pa_str, (char *)ptr + write_ofs, bytes_to_write, NULL, 0LL, PA_SEEK_RELATIVE); if (ret != 0) { - ERR_PRINTS("PulseAudio: pa_stream_write error: " + String(pa_strerror(ret))); + ERR_PRINT("PulseAudio: pa_stream_write error: " + String(pa_strerror(ret))); } else { avail_bytes -= bytes_to_write; write_ofs += bytes_to_write; @@ -666,7 +666,7 @@ Error AudioDriverPulseAudio::capture_init_device() { break; default: - WARN_PRINTS("PulseAudio: Unsupported number of input channels: " + itos(pa_rec_map.channels)); + WARN_PRINT("PulseAudio: Unsupported number of input channels: " + itos(pa_rec_map.channels)); pa_channel_map_init_stereo(&pa_rec_map); break; } @@ -686,7 +686,7 @@ Error AudioDriverPulseAudio::capture_init_device() { pa_rec_str = pa_stream_new(pa_ctx, "Record", &spec, &pa_rec_map); if (pa_rec_str == NULL) { - ERR_PRINTS("PulseAudio: pa_stream_new error: " + String(pa_strerror(pa_context_errno(pa_ctx)))); + ERR_PRINT("PulseAudio: pa_stream_new error: " + String(pa_strerror(pa_context_errno(pa_ctx)))); ERR_FAIL_V(ERR_CANT_OPEN); } @@ -694,7 +694,7 @@ Error AudioDriverPulseAudio::capture_init_device() { pa_stream_flags flags = pa_stream_flags(PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_ADJUST_LATENCY | PA_STREAM_AUTO_TIMING_UPDATE); int error_code = pa_stream_connect_record(pa_rec_str, dev, &attr, flags); if (error_code < 0) { - ERR_PRINTS("PulseAudio: pa_stream_connect_record error: " + String(pa_strerror(error_code))); + ERR_PRINT("PulseAudio: pa_stream_connect_record error: " + String(pa_strerror(error_code))); ERR_FAIL_V(ERR_CANT_OPEN); } @@ -711,7 +711,7 @@ void AudioDriverPulseAudio::capture_finish_device() { if (pa_rec_str) { int ret = pa_stream_disconnect(pa_rec_str); if (ret != 0) { - ERR_PRINTS("PulseAudio: pa_stream_disconnect error: " + String(pa_strerror(ret))); + ERR_PRINT("PulseAudio: pa_stream_disconnect error: " + String(pa_strerror(ret))); } pa_stream_unref(pa_rec_str); pa_rec_str = NULL; diff --git a/drivers/spirv-reflect/SCsub b/drivers/spirv-reflect/SCsub new file mode 100644 index 0000000000..8ff27da114 --- /dev/null +++ b/drivers/spirv-reflect/SCsub @@ -0,0 +1,17 @@ +#!/usr/bin/env python + +Import('env') + +env_spirv_reflect = env.Clone() +env_spirv_reflect.disable_warnings() + +thirdparty_dir = "#thirdparty/spirv-reflect/" +thirdparty_sources = [ + "spirv_reflect.c" +] + +thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources] + +env_spirv_reflect.add_source_files(env.drivers_sources, thirdparty_sources) + +Export('env') diff --git a/drivers/unix/os_unix.cpp b/drivers/unix/os_unix.cpp index c5eb343cc8..2d8d37b2f1 100644 --- a/drivers/unix/os_unix.cpp +++ b/drivers/unix/os_unix.cpp @@ -559,34 +559,34 @@ void UnixTerminalLogger::log_error(const char *p_function, const char *p_file, i // This prevents Godot from writing ANSI escape codes when redirecting // stdout and stderr to a file. const bool tty = isatty(fileno(stdout)); - const char *red = tty ? "\E[0;31m" : ""; + const char *gray = tty ? "\E[0;90m" : ""; + const char *red = tty ? "\E[0;91m" : ""; const char *red_bold = tty ? "\E[1;31m" : ""; - const char *yellow = tty ? "\E[0;33m" : ""; + const char *yellow = tty ? "\E[0;93m" : ""; const char *yellow_bold = tty ? "\E[1;33m" : ""; - const char *magenta = tty ? "\E[0;35m" : ""; + const char *magenta = tty ? "\E[0;95m" : ""; const char *magenta_bold = tty ? "\E[1;35m" : ""; - const char *cyan = tty ? "\E[0;36m" : ""; + const char *cyan = tty ? "\E[0;96m" : ""; const char *cyan_bold = tty ? "\E[1;36m" : ""; const char *reset = tty ? "\E[0m" : ""; - const char *bold = tty ? "\E[1m" : ""; switch (p_type) { case ERR_WARNING: - logf_error("%sWARNING: %s: %s%s%s\n", yellow_bold, p_function, reset, bold, err_details); - logf_error("%s At: %s:%i.%s\n", yellow, p_file, p_line, reset); + logf_error("%sWARNING:%s %s\n", yellow_bold, yellow, err_details); + logf_error("%s at: %s (%s:%i)%s\n", gray, p_function, p_file, p_line, reset); break; case ERR_SCRIPT: - logf_error("%sSCRIPT ERROR: %s: %s%s%s\n", magenta_bold, p_function, reset, bold, err_details); - logf_error("%s At: %s:%i.%s\n", magenta, p_file, p_line, reset); + logf_error("%sSCRIPT ERROR:%s %s\n", magenta_bold, magenta, err_details); + logf_error("%s at: %s (%s:%i)%s\n", gray, p_function, p_file, p_line, reset); break; case ERR_SHADER: - logf_error("%sSHADER ERROR: %s: %s%s%s\n", cyan_bold, p_function, reset, bold, err_details); - logf_error("%s At: %s:%i.%s\n", cyan, p_file, p_line, reset); + logf_error("%sSHADER ERROR:%s %s\n", cyan_bold, cyan, err_details); + logf_error("%s at: %s (%s:%i)%s\n", gray, p_function, p_file, p_line, reset); break; case ERR_ERROR: default: - logf_error("%sERROR: %s: %s%s%s\n", red_bold, p_function, reset, bold, err_details); - logf_error("%s At: %s:%i.%s\n", red, p_file, p_line, reset); + logf_error("%sERROR:%s %s\n", red_bold, red, err_details); + logf_error("%s at: %s (%s:%i)%s\n", gray, p_function, p_file, p_line, reset); break; } } diff --git a/drivers/unix/semaphore_posix.cpp b/drivers/unix/semaphore_posix.cpp index 5f412adea1..b532b09cd6 100644 --- a/drivers/unix/semaphore_posix.cpp +++ b/drivers/unix/semaphore_posix.cpp @@ -62,7 +62,7 @@ int SemaphorePosix::get() const { return val; } -Semaphore *SemaphorePosix::create_semaphore_posix() { +SemaphoreOld *SemaphorePosix::create_semaphore_posix() { return memnew(SemaphorePosix); } diff --git a/drivers/unix/semaphore_posix.h b/drivers/unix/semaphore_posix.h index e06f6316db..2bffe6933d 100644 --- a/drivers/unix/semaphore_posix.h +++ b/drivers/unix/semaphore_posix.h @@ -37,11 +37,11 @@ #include <semaphore.h> -class SemaphorePosix : public Semaphore { +class SemaphorePosix : public SemaphoreOld { mutable sem_t sem; - static Semaphore *create_semaphore_posix(); + static SemaphoreOld *create_semaphore_posix(); public: virtual Error wait(); diff --git a/drivers/vulkan/SCsub b/drivers/vulkan/SCsub new file mode 100644 index 0000000000..2576f68f92 --- /dev/null +++ b/drivers/vulkan/SCsub @@ -0,0 +1,67 @@ +#!/usr/bin/env python + +Import('env') + +env.add_source_files(env.drivers_sources, "*.cpp") + +if env['builtin_vulkan']: + # Use bundled Vulkan headers + thirdparty_dir = "#thirdparty/vulkan" + env.Prepend(CPPPATH=[thirdparty_dir, thirdparty_dir + "/include", thirdparty_dir + "/loader"]) + + # Build Vulkan loader library + env_thirdparty = env.Clone() + env_thirdparty.disable_warnings() + + loader_sources = [ + "cJSON.c", + "debug_utils.c", + "dev_ext_trampoline.c", + "loader.c", + "murmurhash.c", + "phys_dev_ext.c", + "trampoline.c", + "unknown_ext_chain.c", + "wsi.c", + "extension_manual.c", + ] + vma_sources = [thirdparty_dir + "/vk_mem_alloc.cpp"] + + if env['platform'] == "windows": + loader_sources.append("dirent_on_windows.c") + loader_sources.append("dxgi_loader.c") + env_thirdparty.AppendUnique(CPPDEFINES=[ + 'VK_USE_PLATFORM_WIN32_KHR', + 'VULKAN_NON_CMAKE_BUILD', + 'WIN32_LEAN_AND_MEAN', + 'API_NAME=\\"%s\\"' % 'Vulkan' + ]) + if not env.msvc: # Windows 7+, missing in mingw headers + env_thirdparty.AppendUnique(CPPDEFINES=[ + "CM_GETIDLIST_FILTER_CLASS=0x00000200", + "CM_GETIDLIST_FILTER_PRESENT=0x00000100" + ]) + elif env['platform'] == "osx": + env_thirdparty.AppendUnique(CPPDEFINES=[ + 'VK_USE_PLATFORM_MACOS_MVK', + 'VULKAN_NON_CMAKE_BUILD', + 'SYSCONFDIR=\\"%s\\"' % '/etc', + 'FALLBACK_DATA_DIRS=\\"%s\\"' % '/usr/local/share:/usr/share', + 'FALLBACK_CONFIG_DIRS=\\"%s\\"' % '/etc/xdg' + ]) + elif env['platform'] == "x11": + env_thirdparty.AppendUnique(CPPDEFINES=[ + 'VK_USE_PLATFORM_XLIB_KHR', + 'VULKAN_NON_CMAKE_BUILD', + 'SYSCONFDIR=\\"%s\\"' % '/etc', + 'FALLBACK_DATA_DIRS=\\"%s\\"' % '/usr/local/share:/usr/share', + 'FALLBACK_CONFIG_DIRS=\\"%s\\"' % '/etc/xdg' + ]) + import platform + if (platform.system() == "Linux"): + # In glibc since 2.17 and musl libc since 1.1.24. Used by loader.c. + env_thirdparty.AppendUnique(CPPDEFINES=['HAVE_SECURE_GETENV']) + + loader_sources = [thirdparty_dir + "/loader/" + file for file in loader_sources] + env_thirdparty.add_source_files(env.drivers_sources, loader_sources) + env_thirdparty.add_source_files(env.drivers_sources, vma_sources) diff --git a/drivers/vulkan/rendering_device_vulkan.cpp b/drivers/vulkan/rendering_device_vulkan.cpp new file mode 100644 index 0000000000..1eb6f204f2 --- /dev/null +++ b/drivers/vulkan/rendering_device_vulkan.cpp @@ -0,0 +1,7071 @@ +/*************************************************************************/ +/* rendering_device_vulkan.cpp */ +/*************************************************************************/ +/* 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. */ +/*************************************************************************/ + +#include "rendering_device_vulkan.h" +#include "core/hashfuncs.h" +#include "core/os/file_access.h" +#include "core/os/os.h" +#include "core/project_settings.h" +#include "drivers/vulkan/vulkan_context.h" +#include "thirdparty/spirv-reflect/spirv_reflect.h" + +//#define FORCE_FULL_BARRIER + +void RenderingDeviceVulkan::_add_dependency(RID p_id, RID p_depends_on) { + + if (!dependency_map.has(p_depends_on)) { + dependency_map[p_depends_on] = Set<RID>(); + } + + dependency_map[p_depends_on].insert(p_id); + + if (!reverse_dependency_map.has(p_id)) { + reverse_dependency_map[p_id] = Set<RID>(); + } + + reverse_dependency_map[p_id].insert(p_depends_on); +} + +void RenderingDeviceVulkan::_free_dependencies(RID p_id) { + + //direct dependencies must be freed + + Map<RID, Set<RID> >::Element *E = dependency_map.find(p_id); + if (E) { + + while (E->get().size()) { + free(E->get().front()->get()); + } + dependency_map.erase(E); + } + + //reverse depenencies must be unreferenced + E = reverse_dependency_map.find(p_id); + + if (E) { + + for (Set<RID>::Element *F = E->get().front(); F; F = F->next()) { + Map<RID, Set<RID> >::Element *G = dependency_map.find(F->get()); + ERR_CONTINUE(!G); + ERR_CONTINUE(!G->get().has(p_id)); + G->get().erase(p_id); + } + + reverse_dependency_map.erase(E); + } +} + +const VkFormat RenderingDeviceVulkan::vulkan_formats[RenderingDevice::DATA_FORMAT_MAX] = { + VK_FORMAT_R4G4_UNORM_PACK8, + VK_FORMAT_R4G4B4A4_UNORM_PACK16, + VK_FORMAT_B4G4R4A4_UNORM_PACK16, + VK_FORMAT_R5G6B5_UNORM_PACK16, + VK_FORMAT_B5G6R5_UNORM_PACK16, + VK_FORMAT_R5G5B5A1_UNORM_PACK16, + VK_FORMAT_B5G5R5A1_UNORM_PACK16, + VK_FORMAT_A1R5G5B5_UNORM_PACK16, + VK_FORMAT_R8_UNORM, + VK_FORMAT_R8_SNORM, + VK_FORMAT_R8_USCALED, + VK_FORMAT_R8_SSCALED, + VK_FORMAT_R8_UINT, + VK_FORMAT_R8_SINT, + VK_FORMAT_R8_SRGB, + VK_FORMAT_R8G8_UNORM, + VK_FORMAT_R8G8_SNORM, + VK_FORMAT_R8G8_USCALED, + VK_FORMAT_R8G8_SSCALED, + VK_FORMAT_R8G8_UINT, + VK_FORMAT_R8G8_SINT, + VK_FORMAT_R8G8_SRGB, + VK_FORMAT_R8G8B8_UNORM, + VK_FORMAT_R8G8B8_SNORM, + VK_FORMAT_R8G8B8_USCALED, + VK_FORMAT_R8G8B8_SSCALED, + VK_FORMAT_R8G8B8_UINT, + VK_FORMAT_R8G8B8_SINT, + VK_FORMAT_R8G8B8_SRGB, + VK_FORMAT_B8G8R8_UNORM, + VK_FORMAT_B8G8R8_SNORM, + VK_FORMAT_B8G8R8_USCALED, + VK_FORMAT_B8G8R8_SSCALED, + VK_FORMAT_B8G8R8_UINT, + VK_FORMAT_B8G8R8_SINT, + VK_FORMAT_B8G8R8_SRGB, + VK_FORMAT_R8G8B8A8_UNORM, + VK_FORMAT_R8G8B8A8_SNORM, + VK_FORMAT_R8G8B8A8_USCALED, + VK_FORMAT_R8G8B8A8_SSCALED, + VK_FORMAT_R8G8B8A8_UINT, + VK_FORMAT_R8G8B8A8_SINT, + VK_FORMAT_R8G8B8A8_SRGB, + VK_FORMAT_B8G8R8A8_UNORM, + VK_FORMAT_B8G8R8A8_SNORM, + VK_FORMAT_B8G8R8A8_USCALED, + VK_FORMAT_B8G8R8A8_SSCALED, + VK_FORMAT_B8G8R8A8_UINT, + VK_FORMAT_B8G8R8A8_SINT, + VK_FORMAT_B8G8R8A8_SRGB, + VK_FORMAT_A8B8G8R8_UNORM_PACK32, + VK_FORMAT_A8B8G8R8_SNORM_PACK32, + VK_FORMAT_A8B8G8R8_USCALED_PACK32, + VK_FORMAT_A8B8G8R8_SSCALED_PACK32, + VK_FORMAT_A8B8G8R8_UINT_PACK32, + VK_FORMAT_A8B8G8R8_SINT_PACK32, + VK_FORMAT_A8B8G8R8_SRGB_PACK32, + VK_FORMAT_A2R10G10B10_UNORM_PACK32, + VK_FORMAT_A2R10G10B10_SNORM_PACK32, + VK_FORMAT_A2R10G10B10_USCALED_PACK32, + VK_FORMAT_A2R10G10B10_SSCALED_PACK32, + VK_FORMAT_A2R10G10B10_UINT_PACK32, + VK_FORMAT_A2R10G10B10_SINT_PACK32, + VK_FORMAT_A2B10G10R10_UNORM_PACK32, + VK_FORMAT_A2B10G10R10_SNORM_PACK32, + VK_FORMAT_A2B10G10R10_USCALED_PACK32, + VK_FORMAT_A2B10G10R10_SSCALED_PACK32, + VK_FORMAT_A2B10G10R10_UINT_PACK32, + VK_FORMAT_A2B10G10R10_SINT_PACK32, + VK_FORMAT_R16_UNORM, + VK_FORMAT_R16_SNORM, + VK_FORMAT_R16_USCALED, + VK_FORMAT_R16_SSCALED, + VK_FORMAT_R16_UINT, + VK_FORMAT_R16_SINT, + VK_FORMAT_R16_SFLOAT, + VK_FORMAT_R16G16_UNORM, + VK_FORMAT_R16G16_SNORM, + VK_FORMAT_R16G16_USCALED, + VK_FORMAT_R16G16_SSCALED, + VK_FORMAT_R16G16_UINT, + VK_FORMAT_R16G16_SINT, + VK_FORMAT_R16G16_SFLOAT, + VK_FORMAT_R16G16B16_UNORM, + VK_FORMAT_R16G16B16_SNORM, + VK_FORMAT_R16G16B16_USCALED, + VK_FORMAT_R16G16B16_SSCALED, + VK_FORMAT_R16G16B16_UINT, + VK_FORMAT_R16G16B16_SINT, + VK_FORMAT_R16G16B16_SFLOAT, + VK_FORMAT_R16G16B16A16_UNORM, + VK_FORMAT_R16G16B16A16_SNORM, + VK_FORMAT_R16G16B16A16_USCALED, + VK_FORMAT_R16G16B16A16_SSCALED, + VK_FORMAT_R16G16B16A16_UINT, + VK_FORMAT_R16G16B16A16_SINT, + VK_FORMAT_R16G16B16A16_SFLOAT, + VK_FORMAT_R32_UINT, + VK_FORMAT_R32_SINT, + VK_FORMAT_R32_SFLOAT, + VK_FORMAT_R32G32_UINT, + VK_FORMAT_R32G32_SINT, + VK_FORMAT_R32G32_SFLOAT, + VK_FORMAT_R32G32B32_UINT, + VK_FORMAT_R32G32B32_SINT, + VK_FORMAT_R32G32B32_SFLOAT, + VK_FORMAT_R32G32B32A32_UINT, + VK_FORMAT_R32G32B32A32_SINT, + VK_FORMAT_R32G32B32A32_SFLOAT, + VK_FORMAT_R64_UINT, + VK_FORMAT_R64_SINT, + VK_FORMAT_R64_SFLOAT, + VK_FORMAT_R64G64_UINT, + VK_FORMAT_R64G64_SINT, + VK_FORMAT_R64G64_SFLOAT, + VK_FORMAT_R64G64B64_UINT, + VK_FORMAT_R64G64B64_SINT, + VK_FORMAT_R64G64B64_SFLOAT, + VK_FORMAT_R64G64B64A64_UINT, + VK_FORMAT_R64G64B64A64_SINT, + VK_FORMAT_R64G64B64A64_SFLOAT, + VK_FORMAT_B10G11R11_UFLOAT_PACK32, + VK_FORMAT_E5B9G9R9_UFLOAT_PACK32, + VK_FORMAT_D16_UNORM, + VK_FORMAT_X8_D24_UNORM_PACK32, + VK_FORMAT_D32_SFLOAT, + VK_FORMAT_S8_UINT, + VK_FORMAT_D16_UNORM_S8_UINT, + VK_FORMAT_D24_UNORM_S8_UINT, + VK_FORMAT_D32_SFLOAT_S8_UINT, + VK_FORMAT_BC1_RGB_UNORM_BLOCK, + VK_FORMAT_BC1_RGB_SRGB_BLOCK, + VK_FORMAT_BC1_RGBA_UNORM_BLOCK, + VK_FORMAT_BC1_RGBA_SRGB_BLOCK, + VK_FORMAT_BC2_UNORM_BLOCK, + VK_FORMAT_BC2_SRGB_BLOCK, + VK_FORMAT_BC3_UNORM_BLOCK, + VK_FORMAT_BC3_SRGB_BLOCK, + VK_FORMAT_BC4_UNORM_BLOCK, + VK_FORMAT_BC4_SNORM_BLOCK, + VK_FORMAT_BC5_UNORM_BLOCK, + VK_FORMAT_BC5_SNORM_BLOCK, + VK_FORMAT_BC6H_UFLOAT_BLOCK, + VK_FORMAT_BC6H_SFLOAT_BLOCK, + VK_FORMAT_BC7_UNORM_BLOCK, + VK_FORMAT_BC7_SRGB_BLOCK, + VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK, + VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK, + VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK, + VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK, + VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK, + VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK, + VK_FORMAT_EAC_R11_UNORM_BLOCK, + VK_FORMAT_EAC_R11_SNORM_BLOCK, + VK_FORMAT_EAC_R11G11_UNORM_BLOCK, + VK_FORMAT_EAC_R11G11_SNORM_BLOCK, + VK_FORMAT_ASTC_4x4_UNORM_BLOCK, + VK_FORMAT_ASTC_4x4_SRGB_BLOCK, + VK_FORMAT_ASTC_5x4_UNORM_BLOCK, + VK_FORMAT_ASTC_5x4_SRGB_BLOCK, + VK_FORMAT_ASTC_5x5_UNORM_BLOCK, + VK_FORMAT_ASTC_5x5_SRGB_BLOCK, + VK_FORMAT_ASTC_6x5_UNORM_BLOCK, + VK_FORMAT_ASTC_6x5_SRGB_BLOCK, + VK_FORMAT_ASTC_6x6_UNORM_BLOCK, + VK_FORMAT_ASTC_6x6_SRGB_BLOCK, + VK_FORMAT_ASTC_8x5_UNORM_BLOCK, + VK_FORMAT_ASTC_8x5_SRGB_BLOCK, + VK_FORMAT_ASTC_8x6_UNORM_BLOCK, + VK_FORMAT_ASTC_8x6_SRGB_BLOCK, + VK_FORMAT_ASTC_8x8_UNORM_BLOCK, + VK_FORMAT_ASTC_8x8_SRGB_BLOCK, + VK_FORMAT_ASTC_10x5_UNORM_BLOCK, + VK_FORMAT_ASTC_10x5_SRGB_BLOCK, + VK_FORMAT_ASTC_10x6_UNORM_BLOCK, + VK_FORMAT_ASTC_10x6_SRGB_BLOCK, + VK_FORMAT_ASTC_10x8_UNORM_BLOCK, + VK_FORMAT_ASTC_10x8_SRGB_BLOCK, + VK_FORMAT_ASTC_10x10_UNORM_BLOCK, + VK_FORMAT_ASTC_10x10_SRGB_BLOCK, + VK_FORMAT_ASTC_12x10_UNORM_BLOCK, + VK_FORMAT_ASTC_12x10_SRGB_BLOCK, + VK_FORMAT_ASTC_12x12_UNORM_BLOCK, + VK_FORMAT_ASTC_12x12_SRGB_BLOCK, + VK_FORMAT_G8B8G8R8_422_UNORM, + VK_FORMAT_B8G8R8G8_422_UNORM, + VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM, + VK_FORMAT_G8_B8R8_2PLANE_420_UNORM, + VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM, + VK_FORMAT_G8_B8R8_2PLANE_422_UNORM, + VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM, + VK_FORMAT_R10X6_UNORM_PACK16, + VK_FORMAT_R10X6G10X6_UNORM_2PACK16, + VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16, + VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16, + VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16, + VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16, + VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16, + VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16, + VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16, + VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16, + VK_FORMAT_R12X4_UNORM_PACK16, + VK_FORMAT_R12X4G12X4_UNORM_2PACK16, + VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16, + VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16, + VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16, + VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16, + VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16, + VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16, + VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16, + VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16, + VK_FORMAT_G16B16G16R16_422_UNORM, + VK_FORMAT_B16G16R16G16_422_UNORM, + VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM, + VK_FORMAT_G16_B16R16_2PLANE_420_UNORM, + VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM, + VK_FORMAT_G16_B16R16_2PLANE_422_UNORM, + VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM, + VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG, + VK_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG, + VK_FORMAT_PVRTC2_2BPP_UNORM_BLOCK_IMG, + VK_FORMAT_PVRTC2_4BPP_UNORM_BLOCK_IMG, + VK_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG, + VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG, + VK_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG, + VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG, +}; + +const char *RenderingDeviceVulkan::named_formats[RenderingDevice::DATA_FORMAT_MAX] = { + "R4G4_Unorm_Pack8", + "R4G4B4A4_Unorm_Pack16", + "B4G4R4A4_Unorm_Pack16", + "R5G6B5_Unorm_Pack16", + "B5G6R5_Unorm_Pack16", + "R5G5B5A1_Unorm_Pack16", + "B5G5R5A1_Unorm_Pack16", + "A1R5G5B5_Unorm_Pack16", + "R8_Unorm", + "R8_Snorm", + "R8_Uscaled", + "R8_Sscaled", + "R8_Uint", + "R8_Sint", + "R8_Srgb", + "R8G8_Unorm", + "R8G8_Snorm", + "R8G8_Uscaled", + "R8G8_Sscaled", + "R8G8_Uint", + "R8G8_Sint", + "R8G8_Srgb", + "R8G8B8_Unorm", + "R8G8B8_Snorm", + "R8G8B8_Uscaled", + "R8G8B8_Sscaled", + "R8G8B8_Uint", + "R8G8B8_Sint", + "R8G8B8_Srgb", + "B8G8R8_Unorm", + "B8G8R8_Snorm", + "B8G8R8_Uscaled", + "B8G8R8_Sscaled", + "B8G8R8_Uint", + "B8G8R8_Sint", + "B8G8R8_Srgb", + "R8G8B8A8_Unorm", + "R8G8B8A8_Snorm", + "R8G8B8A8_Uscaled", + "R8G8B8A8_Sscaled", + "R8G8B8A8_Uint", + "R8G8B8A8_Sint", + "R8G8B8A8_Srgb", + "B8G8R8A8_Unorm", + "B8G8R8A8_Snorm", + "B8G8R8A8_Uscaled", + "B8G8R8A8_Sscaled", + "B8G8R8A8_Uint", + "B8G8R8A8_Sint", + "B8G8R8A8_Srgb", + "A8B8G8R8_Unorm_Pack32", + "A8B8G8R8_Snorm_Pack32", + "A8B8G8R8_Uscaled_Pack32", + "A8B8G8R8_Sscaled_Pack32", + "A8B8G8R8_Uint_Pack32", + "A8B8G8R8_Sint_Pack32", + "A8B8G8R8_Srgb_Pack32", + "A2R10G10B10_Unorm_Pack32", + "A2R10G10B10_Snorm_Pack32", + "A2R10G10B10_Uscaled_Pack32", + "A2R10G10B10_Sscaled_Pack32", + "A2R10G10B10_Uint_Pack32", + "A2R10G10B10_Sint_Pack32", + "A2B10G10R10_Unorm_Pack32", + "A2B10G10R10_Snorm_Pack32", + "A2B10G10R10_Uscaled_Pack32", + "A2B10G10R10_Sscaled_Pack32", + "A2B10G10R10_Uint_Pack32", + "A2B10G10R10_Sint_Pack32", + "R16_Unorm", + "R16_Snorm", + "R16_Uscaled", + "R16_Sscaled", + "R16_Uint", + "R16_Sint", + "R16_Sfloat", + "R16G16_Unorm", + "R16G16_Snorm", + "R16G16_Uscaled", + "R16G16_Sscaled", + "R16G16_Uint", + "R16G16_Sint", + "R16G16_Sfloat", + "R16G16B16_Unorm", + "R16G16B16_Snorm", + "R16G16B16_Uscaled", + "R16G16B16_Sscaled", + "R16G16B16_Uint", + "R16G16B16_Sint", + "R16G16B16_Sfloat", + "R16G16B16A16_Unorm", + "R16G16B16A16_Snorm", + "R16G16B16A16_Uscaled", + "R16G16B16A16_Sscaled", + "R16G16B16A16_Uint", + "R16G16B16A16_Sint", + "R16G16B16A16_Sfloat", + "R32_Uint", + "R32_Sint", + "R32_Sfloat", + "R32G32_Uint", + "R32G32_Sint", + "R32G32_Sfloat", + "R32G32B32_Uint", + "R32G32B32_Sint", + "R32G32B32_Sfloat", + "R32G32B32A32_Uint", + "R32G32B32A32_Sint", + "R32G32B32A32_Sfloat", + "R64_Uint", + "R64_Sint", + "R64_Sfloat", + "R64G64_Uint", + "R64G64_Sint", + "R64G64_Sfloat", + "R64G64B64_Uint", + "R64G64B64_Sint", + "R64G64B64_Sfloat", + "R64G64B64A64_Uint", + "R64G64B64A64_Sint", + "R64G64B64A64_Sfloat", + "B10G11R11_Ufloat_Pack32", + "E5B9G9R9_Ufloat_Pack32", + "D16_Unorm", + "X8_D24_Unorm_Pack32", + "D32_Sfloat", + "S8_Uint", + "D16_Unorm_S8_Uint", + "D24_Unorm_S8_Uint", + "D32_Sfloat_S8_Uint", + "Bc1_Rgb_Unorm_Block", + "Bc1_Rgb_Srgb_Block", + "Bc1_Rgba_Unorm_Block", + "Bc1_Rgba_Srgb_Block", + "Bc2_Unorm_Block", + "Bc2_Srgb_Block", + "Bc3_Unorm_Block", + "Bc3_Srgb_Block", + "Bc4_Unorm_Block", + "Bc4_Snorm_Block", + "Bc5_Unorm_Block", + "Bc5_Snorm_Block", + "Bc6H_Ufloat_Block", + "Bc6H_Sfloat_Block", + "Bc7_Unorm_Block", + "Bc7_Srgb_Block", + "Etc2_R8G8B8_Unorm_Block", + "Etc2_R8G8B8_Srgb_Block", + "Etc2_R8G8B8A1_Unorm_Block", + "Etc2_R8G8B8A1_Srgb_Block", + "Etc2_R8G8B8A8_Unorm_Block", + "Etc2_R8G8B8A8_Srgb_Block", + "Eac_R11_Unorm_Block", + "Eac_R11_Snorm_Block", + "Eac_R11G11_Unorm_Block", + "Eac_R11G11_Snorm_Block", + "Astc_4X4_Unorm_Block", + "Astc_4X4_Srgb_Block", + "Astc_5X4_Unorm_Block", + "Astc_5X4_Srgb_Block", + "Astc_5X5_Unorm_Block", + "Astc_5X5_Srgb_Block", + "Astc_6X5_Unorm_Block", + "Astc_6X5_Srgb_Block", + "Astc_6X6_Unorm_Block", + "Astc_6X6_Srgb_Block", + "Astc_8X5_Unorm_Block", + "Astc_8X5_Srgb_Block", + "Astc_8X6_Unorm_Block", + "Astc_8X6_Srgb_Block", + "Astc_8X8_Unorm_Block", + "Astc_8X8_Srgb_Block", + "Astc_10X5_Unorm_Block", + "Astc_10X5_Srgb_Block", + "Astc_10X6_Unorm_Block", + "Astc_10X6_Srgb_Block", + "Astc_10X8_Unorm_Block", + "Astc_10X8_Srgb_Block", + "Astc_10X10_Unorm_Block", + "Astc_10X10_Srgb_Block", + "Astc_12X10_Unorm_Block", + "Astc_12X10_Srgb_Block", + "Astc_12X12_Unorm_Block", + "Astc_12X12_Srgb_Block", + "G8B8G8R8_422_Unorm", + "B8G8R8G8_422_Unorm", + "G8_B8_R8_3Plane_420_Unorm", + "G8_B8R8_2Plane_420_Unorm", + "G8_B8_R8_3Plane_422_Unorm", + "G8_B8R8_2Plane_422_Unorm", + "G8_B8_R8_3Plane_444_Unorm", + "R10X6_Unorm_Pack16", + "R10X6G10X6_Unorm_2Pack16", + "R10X6G10X6B10X6A10X6_Unorm_4Pack16", + "G10X6B10X6G10X6R10X6_422_Unorm_4Pack16", + "B10X6G10X6R10X6G10X6_422_Unorm_4Pack16", + "G10X6_B10X6_R10X6_3Plane_420_Unorm_3Pack16", + "G10X6_B10X6R10X6_2Plane_420_Unorm_3Pack16", + "G10X6_B10X6_R10X6_3Plane_422_Unorm_3Pack16", + "G10X6_B10X6R10X6_2Plane_422_Unorm_3Pack16", + "G10X6_B10X6_R10X6_3Plane_444_Unorm_3Pack16", + "R12X4_Unorm_Pack16", + "R12X4G12X4_Unorm_2Pack16", + "R12X4G12X4B12X4A12X4_Unorm_4Pack16", + "G12X4B12X4G12X4R12X4_422_Unorm_4Pack16", + "B12X4G12X4R12X4G12X4_422_Unorm_4Pack16", + "G12X4_B12X4_R12X4_3Plane_420_Unorm_3Pack16", + "G12X4_B12X4R12X4_2Plane_420_Unorm_3Pack16", + "G12X4_B12X4_R12X4_3Plane_422_Unorm_3Pack16", + "G12X4_B12X4R12X4_2Plane_422_Unorm_3Pack16", + "G12X4_B12X4_R12X4_3Plane_444_Unorm_3Pack16", + "G16B16G16R16_422_Unorm", + "B16G16R16G16_422_Unorm", + "G16_B16_R16_3Plane_420_Unorm", + "G16_B16R16_2Plane_420_Unorm", + "G16_B16_R16_3Plane_422_Unorm", + "G16_B16R16_2Plane_422_Unorm", + "G16_B16_R16_3Plane_444_Unorm", + "Pvrtc1_2Bpp_Unorm_Block_Img", + "Pvrtc1_4Bpp_Unorm_Block_Img", + "Pvrtc2_2Bpp_Unorm_Block_Img", + "Pvrtc2_4Bpp_Unorm_Block_Img", + "Pvrtc1_2Bpp_Srgb_Block_Img", + "Pvrtc1_4Bpp_Srgb_Block_Img", + "Pvrtc2_2Bpp_Srgb_Block_Img", + "Pvrtc2_4Bpp_Srgb_Block_Img" +}; + +int RenderingDeviceVulkan::get_format_vertex_size(DataFormat p_format) { + switch (p_format) { + case DATA_FORMAT_R8_UNORM: + case DATA_FORMAT_R8_SNORM: + case DATA_FORMAT_R8_UINT: + case DATA_FORMAT_R8_SINT: + case DATA_FORMAT_R8G8_UNORM: + case DATA_FORMAT_R8G8_SNORM: + case DATA_FORMAT_R8G8_UINT: + case DATA_FORMAT_R8G8_SINT: + case DATA_FORMAT_R8G8B8_UNORM: + case DATA_FORMAT_R8G8B8_SNORM: + case DATA_FORMAT_R8G8B8_UINT: + case DATA_FORMAT_R8G8B8_SINT: + case DATA_FORMAT_B8G8R8_UNORM: + case DATA_FORMAT_B8G8R8_SNORM: + case DATA_FORMAT_B8G8R8_UINT: + case DATA_FORMAT_B8G8R8_SINT: + case DATA_FORMAT_R8G8B8A8_UNORM: + case DATA_FORMAT_R8G8B8A8_SNORM: + case DATA_FORMAT_R8G8B8A8_UINT: + case DATA_FORMAT_R8G8B8A8_SINT: + case DATA_FORMAT_B8G8R8A8_UNORM: + case DATA_FORMAT_B8G8R8A8_SNORM: + case DATA_FORMAT_B8G8R8A8_UINT: + case DATA_FORMAT_B8G8R8A8_SINT: return 4; + case DATA_FORMAT_R16_UNORM: + case DATA_FORMAT_R16_SNORM: + case DATA_FORMAT_R16_UINT: + case DATA_FORMAT_R16_SINT: + case DATA_FORMAT_R16_SFLOAT: return 4; + case DATA_FORMAT_R16G16_UNORM: + case DATA_FORMAT_R16G16_SNORM: + case DATA_FORMAT_R16G16_UINT: + case DATA_FORMAT_R16G16_SINT: + case DATA_FORMAT_R16G16_SFLOAT: return 4; + case DATA_FORMAT_R16G16B16_UNORM: + case DATA_FORMAT_R16G16B16_SNORM: + case DATA_FORMAT_R16G16B16_UINT: + case DATA_FORMAT_R16G16B16_SINT: + case DATA_FORMAT_R16G16B16_SFLOAT: return 8; + case DATA_FORMAT_R16G16B16A16_UNORM: + case DATA_FORMAT_R16G16B16A16_SNORM: + case DATA_FORMAT_R16G16B16A16_UINT: + case DATA_FORMAT_R16G16B16A16_SINT: + case DATA_FORMAT_R16G16B16A16_SFLOAT: return 8; + case DATA_FORMAT_R32_UINT: + case DATA_FORMAT_R32_SINT: + case DATA_FORMAT_R32_SFLOAT: return 4; + case DATA_FORMAT_R32G32_UINT: + case DATA_FORMAT_R32G32_SINT: + case DATA_FORMAT_R32G32_SFLOAT: return 8; + case DATA_FORMAT_R32G32B32_UINT: + case DATA_FORMAT_R32G32B32_SINT: + case DATA_FORMAT_R32G32B32_SFLOAT: return 12; + case DATA_FORMAT_R32G32B32A32_UINT: + case DATA_FORMAT_R32G32B32A32_SINT: + case DATA_FORMAT_R32G32B32A32_SFLOAT: return 16; + case DATA_FORMAT_R64_UINT: + case DATA_FORMAT_R64_SINT: + case DATA_FORMAT_R64_SFLOAT: return 8; + case DATA_FORMAT_R64G64_UINT: + case DATA_FORMAT_R64G64_SINT: + case DATA_FORMAT_R64G64_SFLOAT: return 16; + case DATA_FORMAT_R64G64B64_UINT: + case DATA_FORMAT_R64G64B64_SINT: + case DATA_FORMAT_R64G64B64_SFLOAT: return 24; + case DATA_FORMAT_R64G64B64A64_UINT: + case DATA_FORMAT_R64G64B64A64_SINT: + case DATA_FORMAT_R64G64B64A64_SFLOAT: return 32; + default: return 0; + } +} + +uint32_t RenderingDeviceVulkan::get_image_format_pixel_size(DataFormat p_format) { + + switch (p_format) { + + case DATA_FORMAT_R4G4_UNORM_PACK8: return 1; + case DATA_FORMAT_R4G4B4A4_UNORM_PACK16: + case DATA_FORMAT_B4G4R4A4_UNORM_PACK16: + case DATA_FORMAT_R5G6B5_UNORM_PACK16: + case DATA_FORMAT_B5G6R5_UNORM_PACK16: + case DATA_FORMAT_R5G5B5A1_UNORM_PACK16: + case DATA_FORMAT_B5G5R5A1_UNORM_PACK16: + case DATA_FORMAT_A1R5G5B5_UNORM_PACK16: return 2; + case DATA_FORMAT_R8_UNORM: + case DATA_FORMAT_R8_SNORM: + case DATA_FORMAT_R8_USCALED: + case DATA_FORMAT_R8_SSCALED: + case DATA_FORMAT_R8_UINT: + case DATA_FORMAT_R8_SINT: + case DATA_FORMAT_R8_SRGB: return 1; + case DATA_FORMAT_R8G8_UNORM: + case DATA_FORMAT_R8G8_SNORM: + case DATA_FORMAT_R8G8_USCALED: + case DATA_FORMAT_R8G8_SSCALED: + case DATA_FORMAT_R8G8_UINT: + case DATA_FORMAT_R8G8_SINT: + case DATA_FORMAT_R8G8_SRGB: return 2; + case DATA_FORMAT_R8G8B8_UNORM: + case DATA_FORMAT_R8G8B8_SNORM: + case DATA_FORMAT_R8G8B8_USCALED: + case DATA_FORMAT_R8G8B8_SSCALED: + case DATA_FORMAT_R8G8B8_UINT: + case DATA_FORMAT_R8G8B8_SINT: + case DATA_FORMAT_R8G8B8_SRGB: + case DATA_FORMAT_B8G8R8_UNORM: + case DATA_FORMAT_B8G8R8_SNORM: + case DATA_FORMAT_B8G8R8_USCALED: + case DATA_FORMAT_B8G8R8_SSCALED: + case DATA_FORMAT_B8G8R8_UINT: + case DATA_FORMAT_B8G8R8_SINT: + case DATA_FORMAT_B8G8R8_SRGB: return 3; + case DATA_FORMAT_R8G8B8A8_UNORM: + case DATA_FORMAT_R8G8B8A8_SNORM: + case DATA_FORMAT_R8G8B8A8_USCALED: + case DATA_FORMAT_R8G8B8A8_SSCALED: + case DATA_FORMAT_R8G8B8A8_UINT: + case DATA_FORMAT_R8G8B8A8_SINT: + case DATA_FORMAT_R8G8B8A8_SRGB: + case DATA_FORMAT_B8G8R8A8_UNORM: + case DATA_FORMAT_B8G8R8A8_SNORM: + case DATA_FORMAT_B8G8R8A8_USCALED: + case DATA_FORMAT_B8G8R8A8_SSCALED: + case DATA_FORMAT_B8G8R8A8_UINT: + case DATA_FORMAT_B8G8R8A8_SINT: + case DATA_FORMAT_B8G8R8A8_SRGB: return 4; + case DATA_FORMAT_A8B8G8R8_UNORM_PACK32: + case DATA_FORMAT_A8B8G8R8_SNORM_PACK32: + case DATA_FORMAT_A8B8G8R8_USCALED_PACK32: + case DATA_FORMAT_A8B8G8R8_SSCALED_PACK32: + case DATA_FORMAT_A8B8G8R8_UINT_PACK32: + case DATA_FORMAT_A8B8G8R8_SINT_PACK32: + case DATA_FORMAT_A8B8G8R8_SRGB_PACK32: + case DATA_FORMAT_A2R10G10B10_UNORM_PACK32: + case DATA_FORMAT_A2R10G10B10_SNORM_PACK32: + case DATA_FORMAT_A2R10G10B10_USCALED_PACK32: + case DATA_FORMAT_A2R10G10B10_SSCALED_PACK32: + case DATA_FORMAT_A2R10G10B10_UINT_PACK32: + case DATA_FORMAT_A2R10G10B10_SINT_PACK32: + case DATA_FORMAT_A2B10G10R10_UNORM_PACK32: + case DATA_FORMAT_A2B10G10R10_SNORM_PACK32: + case DATA_FORMAT_A2B10G10R10_USCALED_PACK32: + case DATA_FORMAT_A2B10G10R10_SSCALED_PACK32: + case DATA_FORMAT_A2B10G10R10_UINT_PACK32: + case DATA_FORMAT_A2B10G10R10_SINT_PACK32: return 4; + case DATA_FORMAT_R16_UNORM: + case DATA_FORMAT_R16_SNORM: + case DATA_FORMAT_R16_USCALED: + case DATA_FORMAT_R16_SSCALED: + case DATA_FORMAT_R16_UINT: + case DATA_FORMAT_R16_SINT: + case DATA_FORMAT_R16_SFLOAT: return 2; + case DATA_FORMAT_R16G16_UNORM: + case DATA_FORMAT_R16G16_SNORM: + case DATA_FORMAT_R16G16_USCALED: + case DATA_FORMAT_R16G16_SSCALED: + case DATA_FORMAT_R16G16_UINT: + case DATA_FORMAT_R16G16_SINT: + case DATA_FORMAT_R16G16_SFLOAT: return 4; + case DATA_FORMAT_R16G16B16_UNORM: + case DATA_FORMAT_R16G16B16_SNORM: + case DATA_FORMAT_R16G16B16_USCALED: + case DATA_FORMAT_R16G16B16_SSCALED: + case DATA_FORMAT_R16G16B16_UINT: + case DATA_FORMAT_R16G16B16_SINT: + case DATA_FORMAT_R16G16B16_SFLOAT: return 6; + case DATA_FORMAT_R16G16B16A16_UNORM: + case DATA_FORMAT_R16G16B16A16_SNORM: + case DATA_FORMAT_R16G16B16A16_USCALED: + case DATA_FORMAT_R16G16B16A16_SSCALED: + case DATA_FORMAT_R16G16B16A16_UINT: + case DATA_FORMAT_R16G16B16A16_SINT: + case DATA_FORMAT_R16G16B16A16_SFLOAT: return 8; + case DATA_FORMAT_R32_UINT: + case DATA_FORMAT_R32_SINT: + case DATA_FORMAT_R32_SFLOAT: return 4; + case DATA_FORMAT_R32G32_UINT: + case DATA_FORMAT_R32G32_SINT: + case DATA_FORMAT_R32G32_SFLOAT: return 8; + case DATA_FORMAT_R32G32B32_UINT: + case DATA_FORMAT_R32G32B32_SINT: + case DATA_FORMAT_R32G32B32_SFLOAT: return 12; + case DATA_FORMAT_R32G32B32A32_UINT: + case DATA_FORMAT_R32G32B32A32_SINT: + case DATA_FORMAT_R32G32B32A32_SFLOAT: return 16; + case DATA_FORMAT_R64_UINT: + case DATA_FORMAT_R64_SINT: + case DATA_FORMAT_R64_SFLOAT: return 8; + case DATA_FORMAT_R64G64_UINT: + case DATA_FORMAT_R64G64_SINT: + case DATA_FORMAT_R64G64_SFLOAT: return 16; + case DATA_FORMAT_R64G64B64_UINT: + case DATA_FORMAT_R64G64B64_SINT: + case DATA_FORMAT_R64G64B64_SFLOAT: return 24; + case DATA_FORMAT_R64G64B64A64_UINT: + case DATA_FORMAT_R64G64B64A64_SINT: + case DATA_FORMAT_R64G64B64A64_SFLOAT: return 32; + case DATA_FORMAT_B10G11R11_UFLOAT_PACK32: + case DATA_FORMAT_E5B9G9R9_UFLOAT_PACK32: return 4; + case DATA_FORMAT_D16_UNORM: return 2; + case DATA_FORMAT_X8_D24_UNORM_PACK32: return 4; + case DATA_FORMAT_D32_SFLOAT: return 4; + case DATA_FORMAT_S8_UINT: return 1; + case DATA_FORMAT_D16_UNORM_S8_UINT: return 4; + case DATA_FORMAT_D24_UNORM_S8_UINT: return 4; + case DATA_FORMAT_D32_SFLOAT_S8_UINT: + return 5; //? + case DATA_FORMAT_BC1_RGB_UNORM_BLOCK: + case DATA_FORMAT_BC1_RGB_SRGB_BLOCK: + case DATA_FORMAT_BC1_RGBA_UNORM_BLOCK: + case DATA_FORMAT_BC1_RGBA_SRGB_BLOCK: + case DATA_FORMAT_BC2_UNORM_BLOCK: + case DATA_FORMAT_BC2_SRGB_BLOCK: + case DATA_FORMAT_BC3_UNORM_BLOCK: + case DATA_FORMAT_BC3_SRGB_BLOCK: + case DATA_FORMAT_BC4_UNORM_BLOCK: + case DATA_FORMAT_BC4_SNORM_BLOCK: + case DATA_FORMAT_BC5_UNORM_BLOCK: + case DATA_FORMAT_BC5_SNORM_BLOCK: + case DATA_FORMAT_BC6H_UFLOAT_BLOCK: + case DATA_FORMAT_BC6H_SFLOAT_BLOCK: + case DATA_FORMAT_BC7_UNORM_BLOCK: + case DATA_FORMAT_BC7_SRGB_BLOCK: return 1; + case DATA_FORMAT_ETC2_R8G8B8_UNORM_BLOCK: + case DATA_FORMAT_ETC2_R8G8B8_SRGB_BLOCK: + case DATA_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK: + case DATA_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK: + case DATA_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK: + case DATA_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK: return 1; + case DATA_FORMAT_EAC_R11_UNORM_BLOCK: + case DATA_FORMAT_EAC_R11_SNORM_BLOCK: + case DATA_FORMAT_EAC_R11G11_UNORM_BLOCK: + case DATA_FORMAT_EAC_R11G11_SNORM_BLOCK: return 1; + case DATA_FORMAT_ASTC_4x4_UNORM_BLOCK: + case DATA_FORMAT_ASTC_4x4_SRGB_BLOCK: + case DATA_FORMAT_ASTC_5x4_UNORM_BLOCK: + case DATA_FORMAT_ASTC_5x4_SRGB_BLOCK: + case DATA_FORMAT_ASTC_5x5_UNORM_BLOCK: + case DATA_FORMAT_ASTC_5x5_SRGB_BLOCK: + case DATA_FORMAT_ASTC_6x5_UNORM_BLOCK: + case DATA_FORMAT_ASTC_6x5_SRGB_BLOCK: + case DATA_FORMAT_ASTC_6x6_UNORM_BLOCK: + case DATA_FORMAT_ASTC_6x6_SRGB_BLOCK: + case DATA_FORMAT_ASTC_8x5_UNORM_BLOCK: + case DATA_FORMAT_ASTC_8x5_SRGB_BLOCK: + case DATA_FORMAT_ASTC_8x6_UNORM_BLOCK: + case DATA_FORMAT_ASTC_8x6_SRGB_BLOCK: + case DATA_FORMAT_ASTC_8x8_UNORM_BLOCK: + case DATA_FORMAT_ASTC_8x8_SRGB_BLOCK: + case DATA_FORMAT_ASTC_10x5_UNORM_BLOCK: + case DATA_FORMAT_ASTC_10x5_SRGB_BLOCK: + case DATA_FORMAT_ASTC_10x6_UNORM_BLOCK: + case DATA_FORMAT_ASTC_10x6_SRGB_BLOCK: + case DATA_FORMAT_ASTC_10x8_UNORM_BLOCK: + case DATA_FORMAT_ASTC_10x8_SRGB_BLOCK: + case DATA_FORMAT_ASTC_10x10_UNORM_BLOCK: + case DATA_FORMAT_ASTC_10x10_SRGB_BLOCK: + case DATA_FORMAT_ASTC_12x10_UNORM_BLOCK: + case DATA_FORMAT_ASTC_12x10_SRGB_BLOCK: + case DATA_FORMAT_ASTC_12x12_UNORM_BLOCK: + case DATA_FORMAT_ASTC_12x12_SRGB_BLOCK: return 1; + case DATA_FORMAT_G8B8G8R8_422_UNORM: + case DATA_FORMAT_B8G8R8G8_422_UNORM: return 4; + case DATA_FORMAT_G8_B8_R8_3PLANE_420_UNORM: + case DATA_FORMAT_G8_B8R8_2PLANE_420_UNORM: + case DATA_FORMAT_G8_B8_R8_3PLANE_422_UNORM: + case DATA_FORMAT_G8_B8R8_2PLANE_422_UNORM: + case DATA_FORMAT_G8_B8_R8_3PLANE_444_UNORM: return 4; + case DATA_FORMAT_R10X6_UNORM_PACK16: + case DATA_FORMAT_R10X6G10X6_UNORM_2PACK16: + case DATA_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16: + case DATA_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16: + case DATA_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16: + case DATA_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16: + case DATA_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16: + case DATA_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16: + case DATA_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16: + case DATA_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16: + case DATA_FORMAT_R12X4_UNORM_PACK16: + case DATA_FORMAT_R12X4G12X4_UNORM_2PACK16: + case DATA_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16: + case DATA_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16: + case DATA_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16: + case DATA_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16: + case DATA_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16: + case DATA_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16: + case DATA_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16: + case DATA_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16: return 2; + case DATA_FORMAT_G16B16G16R16_422_UNORM: + case DATA_FORMAT_B16G16R16G16_422_UNORM: + case DATA_FORMAT_G16_B16_R16_3PLANE_420_UNORM: + case DATA_FORMAT_G16_B16R16_2PLANE_420_UNORM: + case DATA_FORMAT_G16_B16_R16_3PLANE_422_UNORM: + case DATA_FORMAT_G16_B16R16_2PLANE_422_UNORM: + case DATA_FORMAT_G16_B16_R16_3PLANE_444_UNORM: return 8; + case DATA_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG: + case DATA_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG: + case DATA_FORMAT_PVRTC2_2BPP_UNORM_BLOCK_IMG: + case DATA_FORMAT_PVRTC2_4BPP_UNORM_BLOCK_IMG: + case DATA_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG: + case DATA_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG: + case DATA_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG: + case DATA_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG: return 1; + default: { + ERR_PRINT("Format not handled, bug"); + } + } + + return 1; +} + +// https://www.khronos.org/registry/DataFormat/specs/1.1/dataformat.1.1.pdf + +void RenderingDeviceVulkan::get_compressed_image_format_block_dimensions(DataFormat p_format, uint32_t &r_w, uint32_t &r_h) { + + switch (p_format) { + case DATA_FORMAT_BC1_RGB_UNORM_BLOCK: + case DATA_FORMAT_BC1_RGB_SRGB_BLOCK: + case DATA_FORMAT_BC1_RGBA_UNORM_BLOCK: + case DATA_FORMAT_BC1_RGBA_SRGB_BLOCK: + case DATA_FORMAT_BC2_UNORM_BLOCK: + case DATA_FORMAT_BC2_SRGB_BLOCK: + case DATA_FORMAT_BC3_UNORM_BLOCK: + case DATA_FORMAT_BC3_SRGB_BLOCK: + case DATA_FORMAT_BC4_UNORM_BLOCK: + case DATA_FORMAT_BC4_SNORM_BLOCK: + case DATA_FORMAT_BC5_UNORM_BLOCK: + case DATA_FORMAT_BC5_SNORM_BLOCK: + case DATA_FORMAT_BC6H_UFLOAT_BLOCK: + case DATA_FORMAT_BC6H_SFLOAT_BLOCK: + case DATA_FORMAT_BC7_UNORM_BLOCK: + case DATA_FORMAT_BC7_SRGB_BLOCK: + case DATA_FORMAT_ETC2_R8G8B8_UNORM_BLOCK: + case DATA_FORMAT_ETC2_R8G8B8_SRGB_BLOCK: + case DATA_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK: + case DATA_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK: + case DATA_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK: + case DATA_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK: + case DATA_FORMAT_EAC_R11_UNORM_BLOCK: + case DATA_FORMAT_EAC_R11_SNORM_BLOCK: + case DATA_FORMAT_EAC_R11G11_UNORM_BLOCK: + case DATA_FORMAT_EAC_R11G11_SNORM_BLOCK: + case DATA_FORMAT_ASTC_4x4_UNORM_BLOCK: //again, not sure about astc + case DATA_FORMAT_ASTC_4x4_SRGB_BLOCK: + case DATA_FORMAT_ASTC_5x4_UNORM_BLOCK: + case DATA_FORMAT_ASTC_5x4_SRGB_BLOCK: + case DATA_FORMAT_ASTC_5x5_UNORM_BLOCK: + case DATA_FORMAT_ASTC_5x5_SRGB_BLOCK: + case DATA_FORMAT_ASTC_6x5_UNORM_BLOCK: + case DATA_FORMAT_ASTC_6x5_SRGB_BLOCK: + case DATA_FORMAT_ASTC_6x6_UNORM_BLOCK: + case DATA_FORMAT_ASTC_6x6_SRGB_BLOCK: + case DATA_FORMAT_ASTC_8x5_UNORM_BLOCK: + case DATA_FORMAT_ASTC_8x5_SRGB_BLOCK: + case DATA_FORMAT_ASTC_8x6_UNORM_BLOCK: + case DATA_FORMAT_ASTC_8x6_SRGB_BLOCK: + case DATA_FORMAT_ASTC_8x8_UNORM_BLOCK: + case DATA_FORMAT_ASTC_8x8_SRGB_BLOCK: + case DATA_FORMAT_ASTC_10x5_UNORM_BLOCK: + case DATA_FORMAT_ASTC_10x5_SRGB_BLOCK: + case DATA_FORMAT_ASTC_10x6_UNORM_BLOCK: + case DATA_FORMAT_ASTC_10x6_SRGB_BLOCK: + case DATA_FORMAT_ASTC_10x8_UNORM_BLOCK: + case DATA_FORMAT_ASTC_10x8_SRGB_BLOCK: + case DATA_FORMAT_ASTC_10x10_UNORM_BLOCK: + case DATA_FORMAT_ASTC_10x10_SRGB_BLOCK: + case DATA_FORMAT_ASTC_12x10_UNORM_BLOCK: + case DATA_FORMAT_ASTC_12x10_SRGB_BLOCK: + case DATA_FORMAT_ASTC_12x12_UNORM_BLOCK: + case DATA_FORMAT_ASTC_12x12_SRGB_BLOCK: + r_w = 4; + r_h = 4; + return; + case DATA_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG: + case DATA_FORMAT_PVRTC2_4BPP_UNORM_BLOCK_IMG: + case DATA_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG: + case DATA_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG: + r_w = 4; + r_h = 4; + return; + case DATA_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG: + case DATA_FORMAT_PVRTC2_2BPP_UNORM_BLOCK_IMG: + case DATA_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG: + case DATA_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG: + r_w = 8; + r_h = 4; + return; + default: { + r_w = 1; + r_h = 1; + } + } +} + +uint32_t RenderingDeviceVulkan::get_compressed_image_format_block_byte_size(DataFormat p_format) { + + switch (p_format) { + case DATA_FORMAT_BC1_RGB_UNORM_BLOCK: + case DATA_FORMAT_BC1_RGB_SRGB_BLOCK: + case DATA_FORMAT_BC1_RGBA_UNORM_BLOCK: + case DATA_FORMAT_BC1_RGBA_SRGB_BLOCK: return 8; + case DATA_FORMAT_BC2_UNORM_BLOCK: + case DATA_FORMAT_BC2_SRGB_BLOCK: return 16; + case DATA_FORMAT_BC3_UNORM_BLOCK: + case DATA_FORMAT_BC3_SRGB_BLOCK: return 16; + case DATA_FORMAT_BC4_UNORM_BLOCK: + case DATA_FORMAT_BC4_SNORM_BLOCK: return 8; + case DATA_FORMAT_BC5_UNORM_BLOCK: + case DATA_FORMAT_BC5_SNORM_BLOCK: return 16; + case DATA_FORMAT_BC6H_UFLOAT_BLOCK: + case DATA_FORMAT_BC6H_SFLOAT_BLOCK: return 16; + case DATA_FORMAT_BC7_UNORM_BLOCK: + case DATA_FORMAT_BC7_SRGB_BLOCK: return 16; + case DATA_FORMAT_ETC2_R8G8B8_UNORM_BLOCK: + case DATA_FORMAT_ETC2_R8G8B8_SRGB_BLOCK: return 8; + case DATA_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK: + case DATA_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK: return 8; + case DATA_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK: + case DATA_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK: return 16; + case DATA_FORMAT_EAC_R11_UNORM_BLOCK: + case DATA_FORMAT_EAC_R11_SNORM_BLOCK: return 8; + case DATA_FORMAT_EAC_R11G11_UNORM_BLOCK: + case DATA_FORMAT_EAC_R11G11_SNORM_BLOCK: return 16; + case DATA_FORMAT_ASTC_4x4_UNORM_BLOCK: //again, not sure about astc + case DATA_FORMAT_ASTC_4x4_SRGB_BLOCK: + case DATA_FORMAT_ASTC_5x4_UNORM_BLOCK: + case DATA_FORMAT_ASTC_5x4_SRGB_BLOCK: + case DATA_FORMAT_ASTC_5x5_UNORM_BLOCK: + case DATA_FORMAT_ASTC_5x5_SRGB_BLOCK: + case DATA_FORMAT_ASTC_6x5_UNORM_BLOCK: + case DATA_FORMAT_ASTC_6x5_SRGB_BLOCK: + case DATA_FORMAT_ASTC_6x6_UNORM_BLOCK: + case DATA_FORMAT_ASTC_6x6_SRGB_BLOCK: + case DATA_FORMAT_ASTC_8x5_UNORM_BLOCK: + case DATA_FORMAT_ASTC_8x5_SRGB_BLOCK: + case DATA_FORMAT_ASTC_8x6_UNORM_BLOCK: + case DATA_FORMAT_ASTC_8x6_SRGB_BLOCK: + case DATA_FORMAT_ASTC_8x8_UNORM_BLOCK: + case DATA_FORMAT_ASTC_8x8_SRGB_BLOCK: + case DATA_FORMAT_ASTC_10x5_UNORM_BLOCK: + case DATA_FORMAT_ASTC_10x5_SRGB_BLOCK: + case DATA_FORMAT_ASTC_10x6_UNORM_BLOCK: + case DATA_FORMAT_ASTC_10x6_SRGB_BLOCK: + case DATA_FORMAT_ASTC_10x8_UNORM_BLOCK: + case DATA_FORMAT_ASTC_10x8_SRGB_BLOCK: + case DATA_FORMAT_ASTC_10x10_UNORM_BLOCK: + case DATA_FORMAT_ASTC_10x10_SRGB_BLOCK: + case DATA_FORMAT_ASTC_12x10_UNORM_BLOCK: + case DATA_FORMAT_ASTC_12x10_SRGB_BLOCK: + case DATA_FORMAT_ASTC_12x12_UNORM_BLOCK: + case DATA_FORMAT_ASTC_12x12_SRGB_BLOCK: + return 8; //wrong + case DATA_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG: + case DATA_FORMAT_PVRTC2_4BPP_UNORM_BLOCK_IMG: + case DATA_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG: + case DATA_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG: + case DATA_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG: + case DATA_FORMAT_PVRTC2_2BPP_UNORM_BLOCK_IMG: + case DATA_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG: + case DATA_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG: + return 8; //what varies is resolution + default: { + } + } + return 1; +} + +uint32_t RenderingDeviceVulkan::get_compressed_image_format_pixel_rshift(DataFormat p_format) { + + switch (p_format) { + case DATA_FORMAT_BC1_RGB_UNORM_BLOCK: //these formats are half byte size, so rshift is 1 + case DATA_FORMAT_BC1_RGB_SRGB_BLOCK: + case DATA_FORMAT_BC1_RGBA_UNORM_BLOCK: + case DATA_FORMAT_BC1_RGBA_SRGB_BLOCK: + case DATA_FORMAT_BC4_UNORM_BLOCK: + case DATA_FORMAT_BC4_SNORM_BLOCK: + case DATA_FORMAT_ETC2_R8G8B8_UNORM_BLOCK: + case DATA_FORMAT_ETC2_R8G8B8_SRGB_BLOCK: + case DATA_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK: + case DATA_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK: + case DATA_FORMAT_EAC_R11_UNORM_BLOCK: + case DATA_FORMAT_EAC_R11_SNORM_BLOCK: + case DATA_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG: + case DATA_FORMAT_PVRTC2_4BPP_UNORM_BLOCK_IMG: + case DATA_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG: + case DATA_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG: return 1; + case DATA_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG: //these formats are quarter byte size, so rshift is 1 + case DATA_FORMAT_PVRTC2_2BPP_UNORM_BLOCK_IMG: + case DATA_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG: + case DATA_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG: return 2; + default: { + } + } + + return 0; +} + +bool RenderingDeviceVulkan::format_has_stencil(DataFormat p_format) { + switch (p_format) { + case DATA_FORMAT_S8_UINT: + case DATA_FORMAT_D16_UNORM_S8_UINT: + case DATA_FORMAT_D24_UNORM_S8_UINT: + case DATA_FORMAT_D32_SFLOAT_S8_UINT: { + return true; + } + default: { + } + } + return false; +} + +uint32_t RenderingDeviceVulkan::get_image_format_required_size(DataFormat p_format, uint32_t p_width, uint32_t p_height, uint32_t p_depth, uint32_t p_mipmaps, uint32_t *r_blockw, uint32_t *r_blockh, uint32_t *r_depth) { + + ERR_FAIL_COND_V(p_mipmaps == 0, 0); + uint32_t w = p_width; + uint32_t h = p_height; + uint32_t d = p_depth; + + uint32_t size = 0; + + uint32_t pixel_size = get_image_format_pixel_size(p_format); + uint32_t pixel_rshift = get_compressed_image_format_pixel_rshift(p_format); + uint32_t blockw, blockh; + get_compressed_image_format_block_dimensions(p_format, blockw, blockh); + + for (uint32_t i = 0; i < p_mipmaps; i++) { + uint32_t bw = w % blockw != 0 ? w + (blockw - w % blockw) : w; + uint32_t bh = h % blockh != 0 ? h + (blockh - h % blockh) : h; + + uint32_t s = bw * bh; + + s *= pixel_size; + s >>= pixel_rshift; + size += s * d; + if (r_blockw) { + *r_blockw = bw; + } + if (r_blockh) { + *r_blockh = bh; + } + if (r_depth) { + *r_depth = d; + } + w = MAX(blockw, w >> 1); + h = MAX(blockh, h >> 1); + d = MAX(1, d >> 1); + } + + return size; +} + +uint32_t RenderingDeviceVulkan::get_image_required_mipmaps(uint32_t p_width, uint32_t p_height, uint32_t p_depth) { + + //formats and block size don't really matter here since they can all go down to 1px (even if block is larger) + int w = p_width; + int h = p_height; + int d = p_depth; + + int mipmaps = 1; + + while (true) { + + if (w == 1 && h == 1 && d == 1) { + break; + } + + w = MAX(1, w >> 1); + h = MAX(1, h >> 1); + d = MAX(1, d >> 1); + + mipmaps++; + }; + + return mipmaps; +} + +/////////////////////// + +const VkCompareOp RenderingDeviceVulkan::compare_operators[RenderingDevice::COMPARE_OP_MAX] = { + VK_COMPARE_OP_NEVER, + VK_COMPARE_OP_LESS, + VK_COMPARE_OP_EQUAL, + VK_COMPARE_OP_LESS_OR_EQUAL, + VK_COMPARE_OP_GREATER, + VK_COMPARE_OP_NOT_EQUAL, + VK_COMPARE_OP_GREATER_OR_EQUAL, + VK_COMPARE_OP_ALWAYS +}; + +const VkStencilOp RenderingDeviceVulkan::stencil_operations[RenderingDevice::STENCIL_OP_MAX] = { + VK_STENCIL_OP_KEEP, + VK_STENCIL_OP_ZERO, + VK_STENCIL_OP_REPLACE, + VK_STENCIL_OP_INCREMENT_AND_CLAMP, + VK_STENCIL_OP_DECREMENT_AND_CLAMP, + VK_STENCIL_OP_INVERT, + VK_STENCIL_OP_INCREMENT_AND_WRAP, + VK_STENCIL_OP_DECREMENT_AND_WRAP +}; + +const VkSampleCountFlagBits RenderingDeviceVulkan::rasterization_sample_count[RenderingDevice::TEXTURE_SAMPLES_MAX] = { + VK_SAMPLE_COUNT_1_BIT, + VK_SAMPLE_COUNT_2_BIT, + VK_SAMPLE_COUNT_4_BIT, + VK_SAMPLE_COUNT_8_BIT, + VK_SAMPLE_COUNT_16_BIT, + VK_SAMPLE_COUNT_32_BIT, + VK_SAMPLE_COUNT_64_BIT, +}; + +const VkLogicOp RenderingDeviceVulkan::logic_operations[RenderingDevice::LOGIC_OP_MAX] = { + VK_LOGIC_OP_CLEAR, + VK_LOGIC_OP_AND, + VK_LOGIC_OP_AND_REVERSE, + VK_LOGIC_OP_COPY, + VK_LOGIC_OP_AND_INVERTED, + VK_LOGIC_OP_NO_OP, + VK_LOGIC_OP_XOR, + VK_LOGIC_OP_OR, + VK_LOGIC_OP_NOR, + VK_LOGIC_OP_EQUIVALENT, + VK_LOGIC_OP_INVERT, + VK_LOGIC_OP_OR_REVERSE, + VK_LOGIC_OP_COPY_INVERTED, + VK_LOGIC_OP_OR_INVERTED, + VK_LOGIC_OP_NAND, + VK_LOGIC_OP_SET +}; + +const VkBlendFactor RenderingDeviceVulkan::blend_factors[RenderingDevice::BLEND_FACTOR_MAX] = { + VK_BLEND_FACTOR_ZERO, + VK_BLEND_FACTOR_ONE, + VK_BLEND_FACTOR_SRC_COLOR, + VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR, + VK_BLEND_FACTOR_DST_COLOR, + VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR, + VK_BLEND_FACTOR_SRC_ALPHA, + VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, + VK_BLEND_FACTOR_DST_ALPHA, + VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA, + VK_BLEND_FACTOR_CONSTANT_COLOR, + VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR, + VK_BLEND_FACTOR_CONSTANT_ALPHA, + VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA, + VK_BLEND_FACTOR_SRC_ALPHA_SATURATE, + VK_BLEND_FACTOR_SRC1_COLOR, + VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR, + VK_BLEND_FACTOR_SRC1_ALPHA, + VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA +}; +const VkBlendOp RenderingDeviceVulkan::blend_operations[RenderingDevice::BLEND_OP_MAX] = { + VK_BLEND_OP_ADD, + VK_BLEND_OP_SUBTRACT, + VK_BLEND_OP_REVERSE_SUBTRACT, + VK_BLEND_OP_MIN, + VK_BLEND_OP_MAX +}; + +const VkSamplerAddressMode RenderingDeviceVulkan::address_modes[RenderingDevice::SAMPLER_REPEAT_MODE_MAX] = { + VK_SAMPLER_ADDRESS_MODE_REPEAT, + VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT, + VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, + VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER, + VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE +}; + +const VkBorderColor RenderingDeviceVulkan::sampler_border_colors[RenderingDevice::SAMPLER_BORDER_COLOR_MAX] = { + VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK, + VK_BORDER_COLOR_INT_TRANSPARENT_BLACK, + VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK, + VK_BORDER_COLOR_INT_OPAQUE_BLACK, + VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE, + VK_BORDER_COLOR_INT_OPAQUE_WHITE +}; + +const VkImageType RenderingDeviceVulkan::vulkan_image_type[RenderingDevice::TEXTURE_TYPE_MAX] = { + VK_IMAGE_TYPE_1D, + VK_IMAGE_TYPE_2D, + VK_IMAGE_TYPE_3D, + VK_IMAGE_TYPE_2D, + VK_IMAGE_TYPE_1D, + VK_IMAGE_TYPE_2D, + VK_IMAGE_TYPE_2D +}; + +/***************************/ +/**** BUFFER MANAGEMENT ****/ +/***************************/ + +Error RenderingDeviceVulkan::_buffer_allocate(Buffer *p_buffer, uint32_t p_size, uint32_t p_usage, VmaMemoryUsage p_mapping) { + VkBufferCreateInfo bufferInfo; + bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + bufferInfo.pNext = NULL; + bufferInfo.flags = 0; + bufferInfo.size = p_size; + bufferInfo.usage = p_usage; + bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + bufferInfo.queueFamilyIndexCount = 0; + bufferInfo.pQueueFamilyIndices = 0; + + VmaAllocationCreateInfo allocInfo; + allocInfo.flags = 0; + allocInfo.usage = p_mapping; + allocInfo.requiredFlags = 0; + allocInfo.preferredFlags = 0; + allocInfo.memoryTypeBits = 0; + allocInfo.pool = NULL; + allocInfo.pUserData = NULL; + + VkResult err = vmaCreateBuffer(allocator, &bufferInfo, &allocInfo, &p_buffer->buffer, &p_buffer->allocation, NULL); + ERR_FAIL_COND_V_MSG(err, ERR_CANT_CREATE, "Can't create buffer of size: " + itos(p_size)); + p_buffer->size = p_size; + p_buffer->buffer_info.buffer = p_buffer->buffer; + p_buffer->buffer_info.offset = 0; + p_buffer->buffer_info.range = p_size; + + return OK; +} + +Error RenderingDeviceVulkan::_buffer_free(Buffer *p_buffer) { + ERR_FAIL_COND_V(p_buffer->size == 0, ERR_INVALID_PARAMETER); + + vmaDestroyBuffer(allocator, p_buffer->buffer, p_buffer->allocation); + p_buffer->buffer = NULL; + p_buffer->allocation = NULL; + p_buffer->size = 0; + + return OK; +} + +Error RenderingDeviceVulkan::_insert_staging_block() { + + VkBufferCreateInfo bufferInfo; + bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + bufferInfo.pNext = NULL; + bufferInfo.flags = 0; + bufferInfo.size = staging_buffer_block_size; + bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; + bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + bufferInfo.queueFamilyIndexCount = 0; + bufferInfo.pQueueFamilyIndices = 0; + + VmaAllocationCreateInfo allocInfo; + allocInfo.flags = 0; + allocInfo.usage = VMA_MEMORY_USAGE_CPU_ONLY; + allocInfo.requiredFlags = 0; + allocInfo.preferredFlags = 0; + allocInfo.memoryTypeBits = 0; + allocInfo.pool = NULL; + allocInfo.pUserData = NULL; + + StagingBufferBlock block; + + VkResult err = vmaCreateBuffer(allocator, &bufferInfo, &allocInfo, &block.buffer, &block.allocation, NULL); + ERR_FAIL_COND_V(err, ERR_CANT_CREATE); + + block.frame_used = 0; + block.fill_amount = 0; + + staging_buffer_blocks.insert(staging_buffer_current, block); + return OK; +} + +Error RenderingDeviceVulkan::_staging_buffer_allocate(uint32_t p_amount, uint32_t p_required_align, uint32_t &r_alloc_offset, uint32_t &r_alloc_size, bool p_can_segment, bool p_on_draw_command_buffer) { + //determine a block to use + + r_alloc_size = p_amount; + + while (true) { + + r_alloc_offset = 0; + + //see if we can use current block + if (staging_buffer_blocks[staging_buffer_current].frame_used == frames_drawn) { + //we used this block this frame, let's see if there is still room + + uint32_t write_from = staging_buffer_blocks[staging_buffer_current].fill_amount; + + { + uint32_t align_remainder = write_from % p_required_align; + if (align_remainder != 0) { + write_from += p_required_align - align_remainder; + } + } + + int32_t available_bytes = int32_t(staging_buffer_block_size) - int32_t(write_from); + + if ((int32_t)p_amount < available_bytes) { + //all is good, we should be ok, all will fit + r_alloc_offset = write_from; + } else if (p_can_segment && available_bytes >= (int32_t)p_required_align) { + //ok all won't fit but at least we can fit a chunkie + //all is good, update what needs to be written to + r_alloc_offset = write_from; + r_alloc_size = available_bytes - (available_bytes % p_required_align); + + } else { + //can't fit it into this buffer. + //will need to try next buffer + + staging_buffer_current = (staging_buffer_current + 1) % staging_buffer_blocks.size(); + + // before doing anything, though, let's check that we didn't manage to fill all blocks + // possible in a single frame + if (staging_buffer_blocks[staging_buffer_current].frame_used == frames_drawn) { + //guess we did.. ok, let's see if we can insert a new block.. + if (staging_buffer_blocks.size() * staging_buffer_block_size < staging_buffer_max_size) { + //we can, so we are safe + Error err = _insert_staging_block(); + if (err) { + return err; + } + //claim for this frame + staging_buffer_blocks.write[staging_buffer_current].frame_used = frames_drawn; + } else { + // Ok, worst case scenario, all the staging buffers belong to this frame + // and this frame is not even done. + // If this is the main thread, it means the user is likely loading a lot of resources at once, + // otherwise, the thread should just be blocked until the next frame (currently unimplemented) + + if (false) { //separate thread from render + + //block_until_next_frame() + continue; + } else { + + //flush EVERYTHING including setup commands. IF not immediate, also need to flush the draw commands + _flush(true); + + //clear the whole staging buffer + for (int i = 0; i < staging_buffer_blocks.size(); i++) { + staging_buffer_blocks.write[i].frame_used = 0; + staging_buffer_blocks.write[i].fill_amount = 0; + } + //claim current + staging_buffer_blocks.write[staging_buffer_current].frame_used = frames_drawn; + } + } + + } else { + //not from current frame, so continue and try again + continue; + } + } + + } else if (staging_buffer_blocks[staging_buffer_current].frame_used <= frames_drawn - frame_count) { + //this is an old block, which was already processed, let's reuse + staging_buffer_blocks.write[staging_buffer_current].frame_used = frames_drawn; + staging_buffer_blocks.write[staging_buffer_current].fill_amount = 0; + } else if (staging_buffer_blocks[staging_buffer_current].frame_used > frames_drawn - frame_count) { + //this block may still be in use, let's not touch it unless we have to, so.. can we create a new one? + if (staging_buffer_blocks.size() * staging_buffer_block_size < staging_buffer_max_size) { + //we are still allowed to create a new block, so let's do that and insert it for current pos + Error err = _insert_staging_block(); + if (err) { + return err; + } + //claim for this frame + staging_buffer_blocks.write[staging_buffer_current].frame_used = frames_drawn; + } else { + // oops, we are out of room and we can't create more. + // let's flush older frames. + // The logic here is that if a game is loading a lot of data from the main thread, it will need to be stalled anyway. + // If loading from a separate thread, we can block that thread until next frame when more room is made (not currently implemented, though). + + if (false) { + //separate thread from render + //block_until_next_frame() + continue; //and try again + } else { + + _flush(false); + + for (int i = 0; i < staging_buffer_blocks.size(); i++) { + //clear all blocks but the ones from this frame + int block_idx = (i + staging_buffer_current) % staging_buffer_blocks.size(); + if (staging_buffer_blocks[block_idx].frame_used == frames_drawn) { + break; //ok, we reached something from this frame, abort + } + + staging_buffer_blocks.write[block_idx].frame_used = 0; + staging_buffer_blocks.write[block_idx].fill_amount = 0; + } + + //claim for current frame + staging_buffer_blocks.write[staging_buffer_current].frame_used = frames_drawn; + } + } + } + + //all was good, break + break; + } + + staging_buffer_used = true; + + return OK; +} + +Error RenderingDeviceVulkan::_buffer_update(Buffer *p_buffer, size_t p_offset, const uint8_t *p_data, size_t p_data_size, bool p_use_draw_command_buffer, uint32_t p_required_align) { + + //submitting may get chunked for various reasons, so convert this to a task + size_t to_submit = p_data_size; + size_t submit_from = 0; + + while (to_submit > 0) { + + uint32_t block_write_offset; + uint32_t block_write_amount; + + Error err = _staging_buffer_allocate(MIN(to_submit, staging_buffer_block_size), p_required_align, block_write_offset, block_write_amount, p_use_draw_command_buffer); + if (err) { + return err; + } + + //map staging buffer (It's CPU and coherent) + + void *data_ptr = NULL; + { + VkResult vkerr = vmaMapMemory(allocator, staging_buffer_blocks[staging_buffer_current].allocation, &data_ptr); + if (vkerr) { + ERR_FAIL_V(ERR_CANT_CREATE); + } + } + + //copy to staging buffer + copymem(((uint8_t *)data_ptr) + block_write_offset, p_data + submit_from, block_write_amount); + + //unmap + vmaUnmapMemory(allocator, staging_buffer_blocks[staging_buffer_current].allocation); + //insert a command to copy this + + VkBufferCopy region; + region.srcOffset = block_write_offset; + region.dstOffset = submit_from + p_offset; + region.size = block_write_amount; + + vkCmdCopyBuffer(p_use_draw_command_buffer ? frames[frame].draw_command_buffer : frames[frame].setup_command_buffer, staging_buffer_blocks[staging_buffer_current].buffer, p_buffer->buffer, 1, ®ion); + + staging_buffer_blocks.write[staging_buffer_current].fill_amount = block_write_offset + block_write_amount; + + to_submit -= block_write_amount; + submit_from += block_write_amount; + } + + return OK; +} + +void RenderingDeviceVulkan::_memory_barrier(VkPipelineStageFlags p_src_stage_mask, VkPipelineStageFlags p_dst_stage_mask, VkAccessFlags p_src_access, VkAccessFlags p_dst_sccess, bool p_sync_with_draw) { + + VkMemoryBarrier mem_barrier; + mem_barrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER; + mem_barrier.pNext = NULL; + mem_barrier.srcAccessMask = p_src_access; + mem_barrier.dstAccessMask = p_dst_sccess; + + vkCmdPipelineBarrier(p_sync_with_draw ? frames[frame].draw_command_buffer : frames[frame].setup_command_buffer, p_src_stage_mask, p_dst_stage_mask, 0, 1, &mem_barrier, 0, NULL, 0, NULL); +} + +void RenderingDeviceVulkan::_full_barrier(bool p_sync_with_draw) { + //used for debug + _memory_barrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, + VK_ACCESS_INDIRECT_COMMAND_READ_BIT | + VK_ACCESS_INDEX_READ_BIT | + VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT | + VK_ACCESS_UNIFORM_READ_BIT | + VK_ACCESS_INPUT_ATTACHMENT_READ_BIT | + VK_ACCESS_SHADER_READ_BIT | + VK_ACCESS_SHADER_WRITE_BIT | + VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | + VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | + VK_ACCESS_TRANSFER_READ_BIT | + VK_ACCESS_TRANSFER_WRITE_BIT | + VK_ACCESS_HOST_READ_BIT | + VK_ACCESS_HOST_WRITE_BIT, + VK_ACCESS_INDIRECT_COMMAND_READ_BIT | + VK_ACCESS_INDEX_READ_BIT | + VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT | + VK_ACCESS_UNIFORM_READ_BIT | + VK_ACCESS_INPUT_ATTACHMENT_READ_BIT | + VK_ACCESS_SHADER_READ_BIT | + VK_ACCESS_SHADER_WRITE_BIT | + VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | + VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | + VK_ACCESS_TRANSFER_READ_BIT | + VK_ACCESS_TRANSFER_WRITE_BIT | + VK_ACCESS_HOST_READ_BIT | + VK_ACCESS_HOST_WRITE_BIT, + p_sync_with_draw); +} + +void RenderingDeviceVulkan::_buffer_memory_barrier(VkBuffer buffer, uint64_t p_from, uint64_t p_size, VkPipelineStageFlags p_src_stage_mask, VkPipelineStageFlags p_dst_stage_mask, VkAccessFlags p_src_access, VkAccessFlags p_dst_sccess, bool p_sync_with_draw) { + + VkBufferMemoryBarrier buffer_mem_barrier; + buffer_mem_barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER; + buffer_mem_barrier.pNext = NULL; + buffer_mem_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + buffer_mem_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + buffer_mem_barrier.srcAccessMask = p_src_access; + buffer_mem_barrier.dstAccessMask = p_dst_sccess; + buffer_mem_barrier.buffer = buffer; + buffer_mem_barrier.offset = p_from; + buffer_mem_barrier.size = p_size; + + vkCmdPipelineBarrier(p_sync_with_draw ? frames[frame].draw_command_buffer : frames[frame].setup_command_buffer, p_src_stage_mask, p_dst_stage_mask, 0, 0, NULL, 1, &buffer_mem_barrier, 0, NULL); +} + +/*****************/ +/**** TEXTURE ****/ +/*****************/ + +RID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const TextureView &p_view, const Vector<PoolVector<uint8_t> > &p_data) { + + _THREAD_SAFE_METHOD_ + + VkImageCreateInfo image_create_info; + image_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; + image_create_info.pNext = NULL; + image_create_info.flags = 0; + + VkImageFormatListCreateInfoKHR format_list_create_info; + Vector<VkFormat> allowed_formats; + + if (p_format.shareable_formats.size()) { + image_create_info.flags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT; + for (int i = 0; i < p_format.shareable_formats.size(); i++) { + allowed_formats.push_back(vulkan_formats[p_format.shareable_formats[i]]); + } + + format_list_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO_KHR; + format_list_create_info.pNext = NULL; + format_list_create_info.viewFormatCount = allowed_formats.size(); + format_list_create_info.pViewFormats = allowed_formats.ptr(); + image_create_info.pNext = &format_list_create_info; + + ERR_FAIL_COND_V_MSG(p_format.shareable_formats.find(p_format.format) == -1, RID(), + "If supplied a list of shareable formats, the current format must be present in the list"); + ERR_FAIL_COND_V_MSG(p_view.format_override != DATA_FORMAT_MAX && p_format.shareable_formats.find(p_view.format_override) == -1, RID(), + "If supplied a list of shareable formats, the current view format override must be present in the list"); + } + if (p_format.type == TEXTURE_TYPE_CUBE || p_format.type == TEXTURE_TYPE_CUBE_ARRAY) { + image_create_info.flags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT; + } + /*if (p_format.type == TEXTURE_TYPE_2D || p_format.type == TEXTURE_TYPE_2D_ARRAY) { + image_create_info.flags |= VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT; + }*/ + + ERR_FAIL_INDEX_V(p_format.type, TEXTURE_TYPE_MAX, RID()); + + image_create_info.imageType = vulkan_image_type[p_format.type]; + + ERR_FAIL_COND_V_MSG(p_format.width < 1, RID(), "Width must be equal or greater than 1 for all textures"); + + image_create_info.format = vulkan_formats[p_format.format]; + + image_create_info.extent.width = p_format.width; + if (image_create_info.imageType == VK_IMAGE_TYPE_3D || image_create_info.imageType == VK_IMAGE_TYPE_2D) { + ERR_FAIL_COND_V_MSG(p_format.height < 1, RID(), "Height must be equal or greater than 1 for 2D and 3D textures"); + image_create_info.extent.height = p_format.height; + } else { + image_create_info.extent.height = 1; + } + + if (image_create_info.imageType == VK_IMAGE_TYPE_3D) { + ERR_FAIL_COND_V_MSG(p_format.depth < 1, RID(), "Depth must be equal or greater than 1 for 3D textures"); + image_create_info.extent.depth = p_format.depth; + } else { + image_create_info.extent.depth = 1; + } + + ERR_FAIL_COND_V(p_format.mipmaps < 1, RID()); + + image_create_info.mipLevels = p_format.mipmaps; + + if (p_format.type == TEXTURE_TYPE_1D_ARRAY || p_format.type == TEXTURE_TYPE_2D_ARRAY || p_format.type == TEXTURE_TYPE_CUBE_ARRAY || p_format.type == TEXTURE_TYPE_CUBE) { + ERR_FAIL_COND_V_MSG(p_format.array_layers < 1, RID(), + "Amount of layers must be equal or greater than 1 for arrays and cubemaps."); + ERR_FAIL_COND_V_MSG((p_format.type == TEXTURE_TYPE_CUBE_ARRAY || p_format.type == TEXTURE_TYPE_CUBE) && (p_format.array_layers % 6) != 0, RID(), + "Cubemap and cubemap array textures must provide a layer number that is multiple of 6"); + image_create_info.arrayLayers = p_format.array_layers; + } else { + image_create_info.arrayLayers = 1; + } + + ERR_FAIL_INDEX_V(p_format.samples, TEXTURE_SAMPLES_MAX, RID()); + + image_create_info.samples = rasterization_sample_count[p_format.samples]; + image_create_info.tiling = (p_format.usage_bits & TEXTURE_USAGE_CPU_READ_BIT) ? VK_IMAGE_TILING_LINEAR : VK_IMAGE_TILING_OPTIMAL; + + //usage + image_create_info.usage = 0; + + if (p_format.usage_bits & TEXTURE_USAGE_SAMPLING_BIT) { + image_create_info.usage |= VK_IMAGE_USAGE_SAMPLED_BIT; + } + + if (p_format.usage_bits & TEXTURE_USAGE_STORAGE_BIT) { + image_create_info.usage |= VK_IMAGE_USAGE_STORAGE_BIT; + } + + if (p_format.usage_bits & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) { + image_create_info.usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + } + + if (p_format.usage_bits & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { + image_create_info.usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; + } + + if (p_format.usage_bits & TEXTURE_USAGE_CAN_UPDATE_BIT) { + image_create_info.usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT; + } + if (p_format.usage_bits & TEXTURE_USAGE_CAN_COPY_FROM_BIT) { + image_create_info.usage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT; + } + + if (p_format.usage_bits & TEXTURE_USAGE_CAN_COPY_TO_BIT) { + image_create_info.usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT; + } + + image_create_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + image_create_info.queueFamilyIndexCount = 0; + image_create_info.pQueueFamilyIndices = NULL; + image_create_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + + uint32_t required_mipmaps = get_image_required_mipmaps(image_create_info.extent.width, image_create_info.extent.height, image_create_info.extent.depth); + + ERR_FAIL_COND_V_MSG(required_mipmaps < image_create_info.mipLevels, RID(), + "Too many mipmaps requested for texture format and dimensions (" + itos(image_create_info.mipLevels) + "), maximum allowed: (" + itos(required_mipmaps) + ")."); + + if (p_data.size()) { + + ERR_FAIL_COND_V_MSG(!(p_format.usage_bits & TEXTURE_USAGE_CAN_UPDATE_BIT), RID(), + "Texture needs the TEXTURE_USAGE_CAN_UPDATE_BIT usage flag in order to be updated at initialization or later"); + + int expected_images = image_create_info.arrayLayers; + ERR_FAIL_COND_V_MSG(p_data.size() != expected_images, RID(), + "Default supplied data for image format is of invalid length (" + itos(p_data.size()) + "), should be (" + itos(expected_images) + ")."); + + for (uint32_t i = 0; i < image_create_info.arrayLayers; i++) { + uint32_t required_size = get_image_format_required_size(p_format.format, image_create_info.extent.width, image_create_info.extent.height, image_create_info.extent.depth, image_create_info.mipLevels); + ERR_FAIL_COND_V_MSG((uint32_t)p_data[i].size() != required_size, RID(), + "Data for slice index " + itos(i) + " (mapped to layer " + itos(i) + ") differs in size (supplied: " + itos(p_data[i].size()) + ") than what is required by the format (" + itos(required_size) + ")."); + } + } + + { + //validate that this image is supported for the intended use + VkFormatProperties properties; + vkGetPhysicalDeviceFormatProperties(context->get_physical_device(), image_create_info.format, &properties); + VkFormatFeatureFlags flags; + + String format_text = "'" + String(named_formats[p_format.format]) + "'"; + + if (p_format.usage_bits & TEXTURE_USAGE_CPU_READ_BIT) { + flags = properties.linearTilingFeatures; + format_text += " (with CPU read bit)"; + } else { + flags = properties.optimalTilingFeatures; + } + + if (p_format.usage_bits & TEXTURE_USAGE_SAMPLING_BIT && !(flags & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT)) { + ERR_FAIL_V_MSG(RID(), "Format " + format_text + " does not support usage as sampling texture."); + } + + if (p_format.usage_bits & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT && !(flags & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT)) { + ERR_FAIL_V_MSG(RID(), "Format " + format_text + " does not support usage as color attachment."); + } + + if (p_format.usage_bits & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT && !(flags & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)) { + printf("vkformat: %x\n", image_create_info.format); + ERR_FAIL_V_MSG(RID(), "Format " + format_text + " does not support usage as depth-stencil attachment."); + } + + if (p_format.usage_bits & TEXTURE_USAGE_STORAGE_BIT && !(flags & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT)) { + ERR_FAIL_V_MSG(RID(), "Format " + format_text + " does not support usage as storage image."); + } + + if (p_format.usage_bits & TEXTURE_USAGE_STORAGE_ATOMIC_BIT && !(flags & VK_FORMAT_FEATURE_STORAGE_IMAGE_ATOMIC_BIT)) { + ERR_FAIL_V_MSG(RID(), "Format " + format_text + " does not support usage as atomic storage image."); + } + } + + //some view validation + + if (p_view.format_override != DATA_FORMAT_MAX) { + ERR_FAIL_INDEX_V(p_view.format_override, DATA_FORMAT_MAX, RID()); + } + ERR_FAIL_INDEX_V(p_view.swizzle_r, TEXTURE_SWIZZLE_MAX, RID()); + ERR_FAIL_INDEX_V(p_view.swizzle_g, TEXTURE_SWIZZLE_MAX, RID()); + ERR_FAIL_INDEX_V(p_view.swizzle_b, TEXTURE_SWIZZLE_MAX, RID()); + ERR_FAIL_INDEX_V(p_view.swizzle_a, TEXTURE_SWIZZLE_MAX, RID()); + + //allocate memory + + VmaAllocationCreateInfo allocInfo; + allocInfo.flags = 0; + allocInfo.usage = p_format.usage_bits & TEXTURE_USAGE_CPU_READ_BIT ? VMA_MEMORY_USAGE_CPU_ONLY : VMA_MEMORY_USAGE_GPU_ONLY; + allocInfo.requiredFlags = 0; + allocInfo.preferredFlags = 0; + allocInfo.memoryTypeBits = 0; + allocInfo.pool = NULL; + allocInfo.pUserData = NULL; + + Texture texture; + + VkResult err = vmaCreateImage(allocator, &image_create_info, &allocInfo, &texture.image, &texture.allocation, &texture.allocation_info); + ERR_FAIL_COND_V(err, RID()); + + texture.type = p_format.type; + texture.format = p_format.format; + texture.width = image_create_info.extent.width; + texture.height = image_create_info.extent.height; + texture.depth = image_create_info.extent.depth; + texture.layers = image_create_info.arrayLayers; + texture.mipmaps = image_create_info.mipLevels; + texture.usage_flags = p_format.usage_bits; + texture.samples = p_format.samples; + texture.allowed_shared_formats = p_format.shareable_formats; + + //set base layout based on usage priority + + if (p_format.usage_bits & TEXTURE_USAGE_SAMPLING_BIT) { + //first priority, readable + texture.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + + } else if (p_format.usage_bits & TEXTURE_USAGE_STORAGE_BIT) { + //second priority, storage + + texture.layout = VK_IMAGE_LAYOUT_GENERAL; + + } else if (p_format.usage_bits & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) { + //third priority, color or depth + + texture.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + + } else if (p_format.usage_bits & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { + + texture.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + + } else { + texture.layout = VK_IMAGE_LAYOUT_GENERAL; + } + + if (p_format.usage_bits & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { + + texture.read_aspect_mask = VK_IMAGE_ASPECT_DEPTH_BIT; + texture.barrier_aspect_mask = VK_IMAGE_ASPECT_DEPTH_BIT; + + if (format_has_stencil(p_format.format)) { + texture.barrier_aspect_mask |= VK_IMAGE_ASPECT_STENCIL_BIT; + } + } else { + texture.read_aspect_mask = VK_IMAGE_ASPECT_COLOR_BIT; + texture.barrier_aspect_mask = VK_IMAGE_ASPECT_COLOR_BIT; + } + + texture.bound = false; + + //create view + + VkImageViewCreateInfo image_view_create_info; + image_view_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + image_view_create_info.pNext = NULL; + image_view_create_info.flags = 0; + image_view_create_info.image = texture.image; + + static const VkImageViewType view_types[TEXTURE_TYPE_MAX] = { + VK_IMAGE_VIEW_TYPE_1D, + VK_IMAGE_VIEW_TYPE_2D, + VK_IMAGE_VIEW_TYPE_3D, + VK_IMAGE_VIEW_TYPE_CUBE, + VK_IMAGE_VIEW_TYPE_1D_ARRAY, + VK_IMAGE_VIEW_TYPE_2D_ARRAY, + VK_IMAGE_VIEW_TYPE_CUBE_ARRAY, + }; + + image_view_create_info.viewType = view_types[p_format.type]; + if (p_view.format_override == DATA_FORMAT_MAX) { + image_view_create_info.format = image_create_info.format; + } else { + image_view_create_info.format = vulkan_formats[p_view.format_override]; + } + + static const VkComponentSwizzle component_swizzles[TEXTURE_SWIZZLE_MAX] = { + VK_COMPONENT_SWIZZLE_IDENTITY, + VK_COMPONENT_SWIZZLE_ZERO, + VK_COMPONENT_SWIZZLE_ONE, + VK_COMPONENT_SWIZZLE_R, + VK_COMPONENT_SWIZZLE_G, + VK_COMPONENT_SWIZZLE_B, + VK_COMPONENT_SWIZZLE_A + }; + + image_view_create_info.components.r = component_swizzles[p_view.swizzle_r]; + image_view_create_info.components.g = component_swizzles[p_view.swizzle_g]; + image_view_create_info.components.b = component_swizzles[p_view.swizzle_b]; + image_view_create_info.components.a = component_swizzles[p_view.swizzle_a]; + + image_view_create_info.subresourceRange.baseMipLevel = 0; + image_view_create_info.subresourceRange.levelCount = image_create_info.mipLevels; + image_view_create_info.subresourceRange.baseArrayLayer = 0; + image_view_create_info.subresourceRange.layerCount = image_create_info.arrayLayers; + if (p_format.usage_bits & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { + image_view_create_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; + } else { + image_view_create_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + } + + err = vkCreateImageView(device, &image_view_create_info, NULL, &texture.view); + + if (err) { + vmaDestroyImage(allocator, texture.image, texture.allocation); + ERR_FAIL_V(RID()); + } + + //barrier to set layout + { + VkImageMemoryBarrier image_memory_barrier; + image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + image_memory_barrier.pNext = NULL; + image_memory_barrier.srcAccessMask = 0; + image_memory_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + image_memory_barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; + image_memory_barrier.newLayout = texture.layout; + image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + image_memory_barrier.image = texture.image; + image_memory_barrier.subresourceRange.aspectMask = texture.barrier_aspect_mask; + image_memory_barrier.subresourceRange.baseMipLevel = 0; + image_memory_barrier.subresourceRange.levelCount = image_create_info.mipLevels; + image_memory_barrier.subresourceRange.baseArrayLayer = 0; + image_memory_barrier.subresourceRange.layerCount = image_create_info.arrayLayers; + + vkCmdPipelineBarrier(frames[frame].setup_command_buffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, NULL, 0, NULL, 1, &image_memory_barrier); + } + + RID id = texture_owner.make_rid(texture); + + if (p_data.size()) { + + for (uint32_t i = 0; i < image_create_info.arrayLayers; i++) { + texture_update(id, i, p_data[i]); + } + } + return id; +} + +RID RenderingDeviceVulkan::texture_create_shared(const TextureView &p_view, RID p_with_texture) { + + _THREAD_SAFE_METHOD_ + + Texture *src_texture = texture_owner.getornull(p_with_texture); + ERR_FAIL_COND_V(!src_texture, RID()); + + if (src_texture->owner.is_valid()) { //ahh this is a share + p_with_texture = src_texture->owner; + src_texture = texture_owner.getornull(src_texture->owner); + ERR_FAIL_COND_V(!src_texture, RID()); //this is a bug + } + + //create view + + Texture texture = *src_texture; + + VkImageViewCreateInfo image_view_create_info; + image_view_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + image_view_create_info.pNext = NULL; + image_view_create_info.flags = 0; + image_view_create_info.image = texture.image; + + static const VkImageViewType view_types[TEXTURE_TYPE_MAX] = { + VK_IMAGE_VIEW_TYPE_1D, + VK_IMAGE_VIEW_TYPE_2D, + VK_IMAGE_VIEW_TYPE_3D, + VK_IMAGE_VIEW_TYPE_CUBE, + VK_IMAGE_VIEW_TYPE_1D_ARRAY, + VK_IMAGE_VIEW_TYPE_2D_ARRAY, + VK_IMAGE_VIEW_TYPE_CUBE_ARRAY, + }; + + image_view_create_info.viewType = view_types[texture.type]; + if (p_view.format_override == DATA_FORMAT_MAX || p_view.format_override == texture.format) { + image_view_create_info.format = vulkan_formats[texture.format]; + } else { + ERR_FAIL_INDEX_V(p_view.format_override, DATA_FORMAT_MAX, RID()); + + ERR_FAIL_COND_V_MSG(texture.allowed_shared_formats.find(p_view.format_override) == -1, RID(), + "Format override is not in the list of allowed shareable formats for original texture."); + image_view_create_info.format = vulkan_formats[p_view.format_override]; + } + + static const VkComponentSwizzle component_swizzles[TEXTURE_SWIZZLE_MAX] = { + VK_COMPONENT_SWIZZLE_IDENTITY, + VK_COMPONENT_SWIZZLE_ZERO, + VK_COMPONENT_SWIZZLE_ONE, + VK_COMPONENT_SWIZZLE_R, + VK_COMPONENT_SWIZZLE_G, + VK_COMPONENT_SWIZZLE_B, + VK_COMPONENT_SWIZZLE_A + }; + + image_view_create_info.components.r = component_swizzles[p_view.swizzle_r]; + image_view_create_info.components.g = component_swizzles[p_view.swizzle_g]; + image_view_create_info.components.b = component_swizzles[p_view.swizzle_b]; + image_view_create_info.components.a = component_swizzles[p_view.swizzle_a]; + + image_view_create_info.subresourceRange.baseMipLevel = 0; + image_view_create_info.subresourceRange.levelCount = texture.mipmaps; + image_view_create_info.subresourceRange.layerCount = texture.layers; + image_view_create_info.subresourceRange.baseArrayLayer = 0; + + if (texture.usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { + image_view_create_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; + } else { + image_view_create_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + } + + VkResult err = vkCreateImageView(device, &image_view_create_info, NULL, &texture.view); + + if (err) { + ERR_FAIL_V(RID()); + } + + texture.owner = p_with_texture; + RID id = texture_owner.make_rid(texture); + _add_dependency(id, p_with_texture); + + return id; +} + +RID RenderingDeviceVulkan::texture_create_shared_from_slice(const TextureView &p_view, RID p_with_texture, uint32_t p_layer, uint32_t p_mipmap, TextureSliceType p_slice_type) { + + _THREAD_SAFE_METHOD_ + + Texture *src_texture = texture_owner.getornull(p_with_texture); + ERR_FAIL_COND_V(!src_texture, RID()); + + if (src_texture->owner.is_valid()) { //ahh this is a share + p_with_texture = src_texture->owner; + src_texture = texture_owner.getornull(src_texture->owner); + ERR_FAIL_COND_V(!src_texture, RID()); //this is a bug + } + + ERR_FAIL_COND_V_MSG(p_slice_type == TEXTURE_SLICE_CUBEMAP && (src_texture->type != TEXTURE_TYPE_CUBE && src_texture->type != TEXTURE_TYPE_CUBE_ARRAY), RID(), + "Can only create a cubemap slice from a cubemap or cubemap array mipmap"); + + ERR_FAIL_COND_V_MSG(p_slice_type == TEXTURE_SLICE_3D && src_texture->type != TEXTURE_TYPE_3D, RID(), + "Can only create a 3D slice from a 3D texture"); + + //create view + + ERR_FAIL_UNSIGNED_INDEX_V(p_mipmap, src_texture->mipmaps, RID()); + ERR_FAIL_UNSIGNED_INDEX_V(p_layer, src_texture->layers, RID()); + + Texture texture = *src_texture; + get_image_format_required_size(texture.format, texture.width, texture.height, texture.depth, p_mipmap + 1, &texture.width, &texture.height); + texture.mipmaps = 1; + texture.layers = p_slice_type == TEXTURE_SLICE_CUBEMAP ? 6 : 1; + + VkImageViewCreateInfo image_view_create_info; + image_view_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + image_view_create_info.pNext = NULL; + image_view_create_info.flags = 0; + image_view_create_info.image = texture.image; + + static const VkImageViewType view_types[TEXTURE_TYPE_MAX] = { + VK_IMAGE_VIEW_TYPE_1D, + VK_IMAGE_VIEW_TYPE_2D, + VK_IMAGE_VIEW_TYPE_2D, + VK_IMAGE_VIEW_TYPE_2D, + VK_IMAGE_VIEW_TYPE_1D, + VK_IMAGE_VIEW_TYPE_2D, + VK_IMAGE_VIEW_TYPE_2D, + }; + + image_view_create_info.viewType = p_slice_type == TEXTURE_SLICE_CUBEMAP ? VK_IMAGE_VIEW_TYPE_CUBE : (p_slice_type == TEXTURE_SLICE_3D ? VK_IMAGE_VIEW_TYPE_3D : view_types[texture.type]); + if (p_view.format_override == DATA_FORMAT_MAX || p_view.format_override == texture.format) { + image_view_create_info.format = vulkan_formats[texture.format]; + } else { + ERR_FAIL_INDEX_V(p_view.format_override, DATA_FORMAT_MAX, RID()); + + ERR_FAIL_COND_V_MSG(texture.allowed_shared_formats.find(p_view.format_override) == -1, RID(), + "Format override is not in the list of allowed shareable formats for original texture."); + image_view_create_info.format = vulkan_formats[p_view.format_override]; + } + + static const VkComponentSwizzle component_swizzles[TEXTURE_SWIZZLE_MAX] = { + VK_COMPONENT_SWIZZLE_IDENTITY, + VK_COMPONENT_SWIZZLE_ZERO, + VK_COMPONENT_SWIZZLE_ONE, + VK_COMPONENT_SWIZZLE_R, + VK_COMPONENT_SWIZZLE_G, + VK_COMPONENT_SWIZZLE_B, + VK_COMPONENT_SWIZZLE_A + }; + + image_view_create_info.components.r = component_swizzles[p_view.swizzle_r]; + image_view_create_info.components.g = component_swizzles[p_view.swizzle_g]; + image_view_create_info.components.b = component_swizzles[p_view.swizzle_b]; + image_view_create_info.components.a = component_swizzles[p_view.swizzle_a]; + + if (p_slice_type == TEXTURE_SLICE_CUBEMAP) { + ERR_FAIL_COND_V_MSG(p_layer >= src_texture->layers, RID(), + "Specified layer is invalid for cubemap"); + ERR_FAIL_COND_V_MSG((p_layer % 6) != 0, RID(), + "Specified layer must be a multiple of 6."); + } + image_view_create_info.subresourceRange.baseMipLevel = p_mipmap; + image_view_create_info.subresourceRange.levelCount = 1; + image_view_create_info.subresourceRange.layerCount = p_slice_type == TEXTURE_SLICE_CUBEMAP ? 6 : 1; + image_view_create_info.subresourceRange.baseArrayLayer = p_layer; + + if (texture.usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { + image_view_create_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; + } else { + image_view_create_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + } + + VkResult err = vkCreateImageView(device, &image_view_create_info, NULL, &texture.view); + + if (err) { + ERR_FAIL_V(RID()); + } + + texture.owner = p_with_texture; + RID id = texture_owner.make_rid(texture); + _add_dependency(id, p_with_texture); + + return id; +} + +Error RenderingDeviceVulkan::texture_update(RID p_texture, uint32_t p_layer, const PoolVector<uint8_t> &p_data, bool p_sync_with_draw) { + + _THREAD_SAFE_METHOD_ + + ERR_FAIL_COND_V_MSG(draw_list && p_sync_with_draw, ERR_INVALID_PARAMETER, + "Updating textures in 'sync to draw' mode is forbidden during creation of a draw list"); + + Texture *texture = texture_owner.getornull(p_texture); + ERR_FAIL_COND_V(!texture, ERR_INVALID_PARAMETER); + + if (texture->owner != RID()) { + p_texture = texture->owner; + texture = texture_owner.getornull(texture->owner); + ERR_FAIL_COND_V(!texture, ERR_BUG); //this is a bug + } + + ERR_FAIL_COND_V_MSG(texture->bound, ERR_CANT_ACQUIRE_RESOURCE, + "Texture can't be updated while a render pass that uses it is being created. Ensure render pass is finalized (and that it was created with RENDER_PASS_CONTENTS_FINISH) to unbind this texture."); + + ERR_FAIL_COND_V_MSG(!(texture->usage_flags & TEXTURE_USAGE_CAN_UPDATE_BIT), ERR_INVALID_PARAMETER, + "Texture requires the TEXTURE_USAGE_CAN_UPDATE_BIT in order to be updatable."); + + uint32_t layer_count = texture->layers; + if (texture->type == TEXTURE_TYPE_CUBE || texture->type == TEXTURE_TYPE_CUBE_ARRAY) { + layer_count *= 6; + } + ERR_FAIL_COND_V(p_layer >= layer_count, ERR_INVALID_PARAMETER); + + uint32_t width, height; + uint32_t image_size = get_image_format_required_size(texture->format, texture->width, texture->height, texture->depth, texture->mipmaps, &width, &height); + uint32_t required_size = image_size; + uint32_t required_align = get_compressed_image_format_block_byte_size(texture->format); + if (required_align == 1) { + required_align = get_image_format_pixel_size(texture->format); + } + if ((required_align % 4) != 0) { //alignment rules are really strange + required_align *= 4; + } + + ERR_FAIL_COND_V_MSG(required_size != (uint32_t)p_data.size(), ERR_INVALID_PARAMETER, + "Required size for texture update (" + itos(required_size) + ") does not match data supplied size (" + itos(p_data.size()) + ")."); + + uint32_t region_size = texture_upload_region_size_px; + + PoolVector<uint8_t>::Read r = p_data.read(); + + VkCommandBuffer command_buffer = p_sync_with_draw ? frames[frame].draw_command_buffer : frames[frame].setup_command_buffer; + + //barrier to transfer + { + VkImageMemoryBarrier image_memory_barrier; + image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + image_memory_barrier.pNext = NULL; + image_memory_barrier.srcAccessMask = 0; + image_memory_barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + image_memory_barrier.oldLayout = texture->layout; + image_memory_barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + + image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + image_memory_barrier.image = texture->image; + image_memory_barrier.subresourceRange.aspectMask = texture->barrier_aspect_mask; + image_memory_barrier.subresourceRange.baseMipLevel = 0; + image_memory_barrier.subresourceRange.levelCount = texture->mipmaps; + image_memory_barrier.subresourceRange.baseArrayLayer = p_layer; + image_memory_barrier.subresourceRange.layerCount = 1; + + vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, NULL, 0, NULL, 1, &image_memory_barrier); + } + + uint32_t mipmap_offset = 0; + for (uint32_t mm_i = 0; mm_i < texture->mipmaps; mm_i++) { + + uint32_t depth; + uint32_t image_total = get_image_format_required_size(texture->format, texture->width, texture->height, texture->depth, mm_i + 1, &width, &height, &depth); + + const uint8_t *read_ptr_mipmap = r.ptr() + mipmap_offset; + image_size = image_total - mipmap_offset; + + for (uint32_t z = 0; z < depth; z++) { //for 3D textures, depth may be > 0 + + const uint8_t *read_ptr = read_ptr_mipmap + image_size * z / depth; + + for (uint32_t x = 0; x < width; x += region_size) { + for (uint32_t y = 0; y < height; y += region_size) { + + uint32_t region_w = MIN(region_size, width - x); + uint32_t region_h = MIN(region_size, height - y); + + uint32_t pixel_size = get_image_format_pixel_size(texture->format); + uint32_t to_allocate = region_w * region_h * pixel_size; + to_allocate >>= get_compressed_image_format_pixel_rshift(texture->format); + + uint32_t alloc_offset, alloc_size; + Error err = _staging_buffer_allocate(to_allocate, required_align, alloc_offset, alloc_size, false, p_sync_with_draw); + ERR_FAIL_COND_V(err, ERR_CANT_CREATE); + + uint8_t *write_ptr; + + { //map + void *data_ptr = NULL; + VkResult vkerr = vmaMapMemory(allocator, staging_buffer_blocks[staging_buffer_current].allocation, &data_ptr); + if (vkerr) { + ERR_FAIL_V(ERR_CANT_CREATE); + } + write_ptr = (uint8_t *)data_ptr; + write_ptr += alloc_offset; + } + + uint32_t block_w, block_h; + get_compressed_image_format_block_dimensions(texture->format, block_w, block_h); + + ERR_FAIL_COND_V(region_w % block_w, ERR_BUG); + ERR_FAIL_COND_V(region_h % block_h, ERR_BUG); + + if (block_w != 1 || block_h != 1) { + //compressed image (blocks) + //must copy a block region + + uint32_t block_size = get_compressed_image_format_block_byte_size(texture->format); + //re-create current variables in blocky format + uint32_t xb = x / block_w; + uint32_t yb = y / block_h; + uint32_t wb = width / block_w; + //uint32_t hb = height / block_h; + uint32_t region_wb = region_w / block_w; + uint32_t region_hb = region_h / block_h; + for (uint32_t xr = 0; xr < region_wb; xr++) { + for (uint32_t yr = 0; yr < region_hb; yr++) { + uint32_t src_offset = ((yr + yb) * wb + xr + xb) * block_size; + uint32_t dst_offset = (yr * region_wb + xr) * block_size; + //copy block + for (uint32_t i = 0; i < block_size; i++) { + write_ptr[dst_offset + i] = read_ptr[src_offset + i]; + } + } + } + + } else { + //regular image (pixels) + //must copy a pixel region + + for (uint32_t xr = 0; xr < region_w; xr++) { + for (uint32_t yr = 0; yr < region_h; yr++) { + uint32_t src_offset = ((yr + y) * width + xr + x) * pixel_size; + uint32_t dst_offset = (yr * region_w + xr) * pixel_size; + //copy block + for (uint32_t i = 0; i < pixel_size; i++) { + + write_ptr[dst_offset + i] = read_ptr[src_offset + i]; + } + } + } + } + + { //unmap + vmaUnmapMemory(allocator, staging_buffer_blocks[staging_buffer_current].allocation); + } + + VkBufferImageCopy buffer_image_copy; + buffer_image_copy.bufferOffset = alloc_offset; + buffer_image_copy.bufferRowLength = 0; //tigthly packed + buffer_image_copy.bufferImageHeight = 0; //tigthly packed + + buffer_image_copy.imageSubresource.aspectMask = texture->read_aspect_mask; + buffer_image_copy.imageSubresource.mipLevel = mm_i; + buffer_image_copy.imageSubresource.baseArrayLayer = p_layer; + buffer_image_copy.imageSubresource.layerCount = 1; + + buffer_image_copy.imageOffset.x = x; + buffer_image_copy.imageOffset.y = y; + buffer_image_copy.imageOffset.z = z; + + buffer_image_copy.imageExtent.width = region_w; + buffer_image_copy.imageExtent.height = region_h; + buffer_image_copy.imageExtent.depth = 1; + + vkCmdCopyBufferToImage(command_buffer, staging_buffer_blocks[staging_buffer_current].buffer, texture->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &buffer_image_copy); + + staging_buffer_blocks.write[staging_buffer_current].fill_amount += alloc_size; + } + } + } + + mipmap_offset = image_total; + } + + //barrier to restore layout + { + VkImageMemoryBarrier image_memory_barrier; + image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + image_memory_barrier.pNext = NULL; + image_memory_barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + image_memory_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + image_memory_barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + image_memory_barrier.newLayout = texture->layout; + image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + image_memory_barrier.image = texture->image; + image_memory_barrier.subresourceRange.aspectMask = texture->barrier_aspect_mask; + image_memory_barrier.subresourceRange.baseMipLevel = 0; + image_memory_barrier.subresourceRange.levelCount = texture->mipmaps; + image_memory_barrier.subresourceRange.baseArrayLayer = p_layer; + image_memory_barrier.subresourceRange.layerCount = 1; + + vkCmdPipelineBarrier(command_buffer, VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, NULL, 0, NULL, 1, &image_memory_barrier); + } + + return OK; +} + +PoolVector<uint8_t> RenderingDeviceVulkan::_texture_get_data_from_image(Texture *tex, VkImage p_image, VmaAllocation p_allocation, uint32_t p_layer, bool p_2d) { + + uint32_t width, height, depth; + uint32_t image_size = get_image_format_required_size(tex->format, tex->width, tex->height, p_2d ? 1 : tex->depth, tex->mipmaps, &width, &height, &depth); + + PoolVector<uint8_t> image_data; + image_data.resize(image_size); + + void *img_mem; + vmaMapMemory(allocator, p_allocation, &img_mem); + + uint32_t blockw, blockh; + get_compressed_image_format_block_dimensions(tex->format, blockw, blockh); + uint32_t block_size = get_compressed_image_format_block_byte_size(tex->format); + uint32_t pixel_size = get_image_format_pixel_size(tex->format); + + { + PoolVector<uint8_t>::Write w = image_data.write(); + + uint32_t mipmap_offset = 0; + for (uint32_t mm_i = 0; mm_i < tex->mipmaps; mm_i++) { + + uint32_t image_total = get_image_format_required_size(tex->format, tex->width, tex->height, p_2d ? 1 : tex->depth, mm_i + 1, &width, &height, &depth); + + uint8_t *write_ptr_mipmap = w.ptr() + mipmap_offset; + image_size = image_total - mipmap_offset; + + VkImageSubresource image_sub_resorce; + image_sub_resorce.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + image_sub_resorce.arrayLayer = p_layer; + image_sub_resorce.mipLevel = mm_i; + VkSubresourceLayout layout; + vkGetImageSubresourceLayout(device, p_image, &image_sub_resorce, &layout); + + for (uint32_t z = 0; z < depth; z++) { + uint8_t *write_ptr = write_ptr_mipmap + z * image_size / depth; + const uint8_t *slice_read_ptr = ((uint8_t *)img_mem) + layout.offset + z * layout.depthPitch; + + if (block_size > 1) { + //compressed + uint32_t line_width = (block_size * (width / blockw)); + for (uint32_t y = 0; y < height / blockh; y++) { + const uint8_t *rptr = slice_read_ptr + y * layout.rowPitch; + uint8_t *wptr = write_ptr + y * line_width; + + copymem(wptr, rptr, line_width); + } + + } else { + //uncompressed + for (uint32_t y = 0; y < height; y++) { + const uint8_t *rptr = slice_read_ptr + y * layout.rowPitch; + uint8_t *wptr = write_ptr + y * pixel_size * width; + copymem(wptr, rptr, pixel_size * width); + } + } + } + + mipmap_offset = image_total; + } + } + + vmaUnmapMemory(allocator, p_allocation); + + return image_data; +} + +PoolVector<uint8_t> RenderingDeviceVulkan::texture_get_data(RID p_texture, uint32_t p_layer) { + + _THREAD_SAFE_METHOD_ + + Texture *tex = texture_owner.getornull(p_texture); + ERR_FAIL_COND_V(!tex, PoolVector<uint8_t>()); + + ERR_FAIL_COND_V_MSG(tex->bound, PoolVector<uint8_t>(), + "Texture can't be retrieved while a render pass that uses it is being created. Ensure render pass is finalized (and that it was created with RENDER_PASS_CONTENTS_FINISH) to unbind this texture."); + ERR_FAIL_COND_V_MSG(!(tex->usage_flags & TEXTURE_USAGE_CAN_COPY_FROM_BIT), PoolVector<uint8_t>(), + "Texture requires the TEXTURE_USAGE_CAN_COPY_FROM_BIT in order to be retrieved."); + + uint32_t layer_count = tex->layers; + if (tex->type == TEXTURE_TYPE_CUBE || tex->type == TEXTURE_TYPE_CUBE_ARRAY) { + layer_count *= 6; + } + ERR_FAIL_COND_V(p_layer >= layer_count, PoolVector<uint8_t>()); + + if (tex->usage_flags & TEXTURE_USAGE_CPU_READ_BIT) { + //does not need anything fancy, map and read. + return _texture_get_data_from_image(tex, tex->image, tex->allocation, p_layer); + } else { + + //compute total image size + uint32_t width, height, depth; + uint32_t buffer_size = get_image_format_required_size(tex->format, tex->width, tex->height, tex->depth, tex->mipmaps, &width, &height, &depth); + + //allocate buffer + VkCommandBuffer command_buffer = frames[frame].setup_command_buffer; + Buffer tmp_buffer; + _buffer_allocate(&tmp_buffer, buffer_size, VK_BUFFER_USAGE_TRANSFER_DST_BIT, VMA_MEMORY_USAGE_CPU_ONLY); + + { //Source image barrier + VkImageMemoryBarrier image_memory_barrier; + image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + image_memory_barrier.pNext = NULL; + image_memory_barrier.srcAccessMask = 0; + image_memory_barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; + image_memory_barrier.oldLayout = tex->layout; + image_memory_barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; + + image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + image_memory_barrier.image = tex->image; + image_memory_barrier.subresourceRange.aspectMask = tex->barrier_aspect_mask; + image_memory_barrier.subresourceRange.baseMipLevel = 0; + image_memory_barrier.subresourceRange.levelCount = tex->mipmaps; + image_memory_barrier.subresourceRange.baseArrayLayer = p_layer; + image_memory_barrier.subresourceRange.layerCount = 1; + + vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, NULL, 0, NULL, 1, &image_memory_barrier); + } + + uint32_t computed_w = tex->width; + uint32_t computed_h = tex->height; + uint32_t computed_d = tex->depth; + + uint32_t prev_size = 0; + uint32_t offset = 0; + for (uint32_t i = 0; i < tex->mipmaps; i++) { + + VkBufferImageCopy buffer_image_copy; + + uint32_t image_size = get_image_format_required_size(tex->format, tex->width, tex->height, tex->depth, i + 1); + uint32_t size = image_size - prev_size; + prev_size = image_size; + + buffer_image_copy.bufferOffset = offset; + buffer_image_copy.bufferImageHeight = 0; + buffer_image_copy.bufferRowLength = 0; + buffer_image_copy.imageSubresource.aspectMask = tex->read_aspect_mask; + buffer_image_copy.imageSubresource.baseArrayLayer = p_layer; + buffer_image_copy.imageSubresource.layerCount = 1; + buffer_image_copy.imageSubresource.mipLevel = i; + buffer_image_copy.imageOffset.x = 0; + buffer_image_copy.imageOffset.y = 0; + buffer_image_copy.imageOffset.z = 0; + buffer_image_copy.imageExtent.width = computed_w; + buffer_image_copy.imageExtent.height = computed_h; + buffer_image_copy.imageExtent.depth = computed_d; + + vkCmdCopyImageToBuffer(command_buffer, tex->image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, tmp_buffer.buffer, 1, &buffer_image_copy); + + computed_w = MAX(1, computed_w >> 1); + computed_h = MAX(1, computed_h >> 1); + computed_d = MAX(1, computed_d >> 1); + offset += size; + } + + { //restore src + VkImageMemoryBarrier image_memory_barrier; + image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + image_memory_barrier.pNext = NULL; + image_memory_barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT; + image_memory_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + image_memory_barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; + image_memory_barrier.newLayout = tex->layout; + image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + image_memory_barrier.image = tex->image; + image_memory_barrier.subresourceRange.aspectMask = tex->barrier_aspect_mask; + image_memory_barrier.subresourceRange.baseMipLevel = 0; + image_memory_barrier.subresourceRange.levelCount = tex->mipmaps; + image_memory_barrier.subresourceRange.baseArrayLayer = p_layer; + image_memory_barrier.subresourceRange.layerCount = 1; + + vkCmdPipelineBarrier(command_buffer, VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, NULL, 0, NULL, 1, &image_memory_barrier); + } + + _flush(true); + + void *buffer_mem; + VkResult vkerr = vmaMapMemory(allocator, tmp_buffer.allocation, &buffer_mem); + if (vkerr) { + ERR_FAIL_V(PoolVector<uint8_t>()); + } + + PoolVector<uint8_t> buffer_data; + { + + buffer_data.resize(buffer_size); + PoolVector<uint8_t>::Write w = buffer_data.write(); + copymem(w.ptr(), buffer_mem, buffer_size); + } + + vmaUnmapMemory(allocator, tmp_buffer.allocation); + + _buffer_free(&tmp_buffer); + + return buffer_data; + } +} + +bool RenderingDeviceVulkan::texture_is_shared(RID p_texture) { + _THREAD_SAFE_METHOD_ + + Texture *tex = texture_owner.getornull(p_texture); + ERR_FAIL_COND_V(!tex, false); + return tex->owner.is_valid(); +} + +bool RenderingDeviceVulkan::texture_is_valid(RID p_texture) { + return texture_owner.owns(p_texture); +} + +Error RenderingDeviceVulkan::texture_copy(RID p_from_texture, RID p_to_texture, const Vector3 &p_from, const Vector3 &p_to, const Vector3 &p_size, uint32_t p_src_mipmap, uint32_t p_dst_mipmap, uint32_t p_src_layer, uint32_t p_dst_layer, bool p_sync_with_draw) { + + _THREAD_SAFE_METHOD_ + + Texture *src_tex = texture_owner.getornull(p_from_texture); + ERR_FAIL_COND_V(!src_tex, ERR_INVALID_PARAMETER); + + ERR_FAIL_COND_V_MSG(p_sync_with_draw && src_tex->bound, ERR_INVALID_PARAMETER, + "Source texture can't be copied while a render pass that uses it is being created. Ensure render pass is finalized (and that it was created with RENDER_PASS_CONTENTS_FINISH) to unbind this texture."); + ERR_FAIL_COND_V_MSG(!(src_tex->usage_flags & TEXTURE_USAGE_CAN_COPY_FROM_BIT), ERR_INVALID_PARAMETER, + "Source texture requires the TEXTURE_USAGE_CAN_COPY_FROM_BIT in order to be retrieved."); + + uint32_t src_layer_count = src_tex->layers; + uint32_t src_width, src_height, src_depth; + get_image_format_required_size(src_tex->format, src_tex->width, src_tex->height, src_tex->depth, p_src_mipmap + 1, &src_width, &src_height, &src_depth); + if (src_tex->type == TEXTURE_TYPE_CUBE || src_tex->type == TEXTURE_TYPE_CUBE_ARRAY) { + src_layer_count *= 6; + } + + ERR_FAIL_COND_V(p_from.x < 0 || p_from.x + p_size.x > src_width, ERR_INVALID_PARAMETER); + ERR_FAIL_COND_V(p_from.y < 0 || p_from.y + p_size.y > src_height, ERR_INVALID_PARAMETER); + ERR_FAIL_COND_V(p_from.z < 0 || p_from.z + p_size.z > src_depth, ERR_INVALID_PARAMETER); + ERR_FAIL_COND_V(p_src_mipmap >= src_tex->mipmaps, ERR_INVALID_PARAMETER); + ERR_FAIL_COND_V(p_src_layer >= src_layer_count, ERR_INVALID_PARAMETER); + + Texture *dst_tex = texture_owner.getornull(p_to_texture); + ERR_FAIL_COND_V(!dst_tex, ERR_INVALID_PARAMETER); + + ERR_FAIL_COND_V_MSG(p_sync_with_draw && dst_tex->bound, ERR_INVALID_PARAMETER, + "Destination texture can't be copied while a render pass that uses it is being created. Ensure render pass is finalized (and that it was created with RENDER_PASS_CONTENTS_FINISH) to unbind this texture."); + ERR_FAIL_COND_V_MSG(!(dst_tex->usage_flags & TEXTURE_USAGE_CAN_COPY_TO_BIT), ERR_INVALID_PARAMETER, + "Destination texture requires the TEXTURE_USAGE_CAN_COPY_TO_BIT in order to be retrieved."); + + uint32_t dst_layer_count = dst_tex->layers; + uint32_t dst_width, dst_height, dst_depth; + get_image_format_required_size(dst_tex->format, dst_tex->width, dst_tex->height, dst_tex->depth, p_dst_mipmap + 1, &dst_width, &dst_height, &dst_depth); + if (dst_tex->type == TEXTURE_TYPE_CUBE || dst_tex->type == TEXTURE_TYPE_CUBE_ARRAY) { + dst_layer_count *= 6; + } + + ERR_FAIL_COND_V(p_to.x < 0 || p_to.x + p_size.x > dst_width, ERR_INVALID_PARAMETER); + ERR_FAIL_COND_V(p_to.y < 0 || p_to.y + p_size.y > dst_height, ERR_INVALID_PARAMETER); + ERR_FAIL_COND_V(p_to.z < 0 || p_to.z + p_size.z > dst_depth, ERR_INVALID_PARAMETER); + ERR_FAIL_COND_V(p_dst_mipmap >= dst_tex->mipmaps, ERR_INVALID_PARAMETER); + ERR_FAIL_COND_V(p_dst_layer >= dst_layer_count, ERR_INVALID_PARAMETER); + + ERR_FAIL_COND_V_MSG(src_tex->read_aspect_mask != dst_tex->read_aspect_mask, ERR_INVALID_PARAMETER, + "Source and destination texture must be of the same type (color or depth)."); + + VkCommandBuffer command_buffer = p_sync_with_draw ? frames[frame].draw_command_buffer : frames[frame].setup_command_buffer; + + { + + //PRE Copy the image + + { //Source + VkImageMemoryBarrier image_memory_barrier; + image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + image_memory_barrier.pNext = NULL; + image_memory_barrier.srcAccessMask = 0; + image_memory_barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; + image_memory_barrier.oldLayout = src_tex->layout; + image_memory_barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; + + image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + image_memory_barrier.image = src_tex->image; + image_memory_barrier.subresourceRange.aspectMask = src_tex->barrier_aspect_mask; + image_memory_barrier.subresourceRange.baseMipLevel = p_src_mipmap; + image_memory_barrier.subresourceRange.levelCount = 1; + image_memory_barrier.subresourceRange.baseArrayLayer = p_src_layer; + image_memory_barrier.subresourceRange.layerCount = 1; + + vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, NULL, 0, NULL, 1, &image_memory_barrier); + } + { //Dest + VkImageMemoryBarrier image_memory_barrier; + image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + image_memory_barrier.pNext = NULL; + image_memory_barrier.srcAccessMask = 0; + image_memory_barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + image_memory_barrier.oldLayout = dst_tex->layout; + image_memory_barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + + image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + image_memory_barrier.image = dst_tex->image; + image_memory_barrier.subresourceRange.aspectMask = dst_tex->read_aspect_mask; + image_memory_barrier.subresourceRange.baseMipLevel = p_dst_mipmap; + image_memory_barrier.subresourceRange.levelCount = 1; + image_memory_barrier.subresourceRange.baseArrayLayer = p_dst_layer; + image_memory_barrier.subresourceRange.layerCount = 1; + + vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, NULL, 0, NULL, 1, &image_memory_barrier); + } + + //COPY + + { + + VkImageCopy image_copy_region; + image_copy_region.srcSubresource.aspectMask = src_tex->read_aspect_mask; + image_copy_region.srcSubresource.baseArrayLayer = p_src_layer; + image_copy_region.srcSubresource.layerCount = 1; + image_copy_region.srcSubresource.mipLevel = p_src_mipmap; + image_copy_region.srcOffset.x = p_from.x; + image_copy_region.srcOffset.y = p_from.y; + image_copy_region.srcOffset.z = p_from.z; + + image_copy_region.dstSubresource.aspectMask = dst_tex->read_aspect_mask; + image_copy_region.dstSubresource.baseArrayLayer = p_dst_layer; + image_copy_region.dstSubresource.layerCount = 1; + image_copy_region.dstSubresource.mipLevel = p_dst_mipmap; + image_copy_region.dstOffset.x = p_to.x; + image_copy_region.dstOffset.y = p_to.y; + image_copy_region.dstOffset.z = p_to.z; + + image_copy_region.extent.width = p_size.x; + image_copy_region.extent.height = p_size.y; + image_copy_region.extent.depth = p_size.z; + + vkCmdCopyImage(command_buffer, src_tex->image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dst_tex->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &image_copy_region); + } + + // RESTORE LAYOUT for SRC and DST + + { //restore src + VkImageMemoryBarrier image_memory_barrier; + image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + image_memory_barrier.pNext = NULL; + image_memory_barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT; + image_memory_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; + image_memory_barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; + image_memory_barrier.newLayout = src_tex->layout; + image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + image_memory_barrier.image = src_tex->image; + image_memory_barrier.subresourceRange.aspectMask = src_tex->barrier_aspect_mask; + image_memory_barrier.subresourceRange.baseMipLevel = p_src_mipmap; + image_memory_barrier.subresourceRange.levelCount = src_tex->mipmaps; + image_memory_barrier.subresourceRange.baseArrayLayer = p_src_layer; + image_memory_barrier.subresourceRange.layerCount = 1; + + vkCmdPipelineBarrier(command_buffer, VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, NULL, 0, NULL, 1, &image_memory_barrier); + } + + { //make dst readable + + VkImageMemoryBarrier image_memory_barrier; + image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + image_memory_barrier.pNext = NULL; + image_memory_barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + image_memory_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; + image_memory_barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + image_memory_barrier.newLayout = dst_tex->layout; + + image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + image_memory_barrier.image = dst_tex->image; + image_memory_barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + image_memory_barrier.subresourceRange.baseMipLevel = p_src_mipmap; + image_memory_barrier.subresourceRange.levelCount = 1; + image_memory_barrier.subresourceRange.baseArrayLayer = p_src_layer; + image_memory_barrier.subresourceRange.layerCount = 1; + + vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, NULL, 0, NULL, 1, &image_memory_barrier); + } + } + + return OK; +} + +Error RenderingDeviceVulkan::texture_clear(RID p_texture, const Color &p_color, uint32_t p_base_mipmap, uint32_t p_mipmaps, uint32_t p_base_layer, uint32_t p_layers, bool p_sync_with_draw) { + + _THREAD_SAFE_METHOD_ + + Texture *src_tex = texture_owner.getornull(p_texture); + ERR_FAIL_COND_V(!src_tex, ERR_INVALID_PARAMETER); + + ERR_FAIL_COND_V_MSG(p_sync_with_draw && src_tex->bound, ERR_INVALID_PARAMETER, + "Source texture can't be cleared while a render pass that uses it is being created. Ensure render pass is finalized (and that it was created with RENDER_PASS_CONTENTS_FINISH) to unbind this texture."); + + ERR_FAIL_COND_V(p_layers == 0, ERR_INVALID_PARAMETER); + ERR_FAIL_COND_V(p_mipmaps == 0, ERR_INVALID_PARAMETER); + + ERR_FAIL_COND_V_MSG(!(src_tex->usage_flags & TEXTURE_USAGE_CAN_COPY_TO_BIT), ERR_INVALID_PARAMETER, + "Source texture requires the TEXTURE_USAGE_CAN_COPY_TO_BIT in order to be cleared."); + + uint32_t src_layer_count = src_tex->layers; + if (src_tex->type == TEXTURE_TYPE_CUBE || src_tex->type == TEXTURE_TYPE_CUBE_ARRAY) { + src_layer_count *= 6; + } + + ERR_FAIL_COND_V(p_base_mipmap + p_mipmaps > src_tex->mipmaps, ERR_INVALID_PARAMETER); + ERR_FAIL_COND_V(p_base_layer + p_layers > src_layer_count, ERR_INVALID_PARAMETER); + + VkCommandBuffer command_buffer = p_sync_with_draw ? frames[frame].draw_command_buffer : frames[frame].setup_command_buffer; + + VkImageLayout layout = src_tex->layout; + + if (src_tex->layout != VK_IMAGE_LAYOUT_GENERAL) { //storage may be in general state + VkImageMemoryBarrier image_memory_barrier; + image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + image_memory_barrier.pNext = NULL; + image_memory_barrier.srcAccessMask = 0; + image_memory_barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + image_memory_barrier.oldLayout = src_tex->layout; + image_memory_barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + + image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + image_memory_barrier.image = src_tex->image; + image_memory_barrier.subresourceRange.aspectMask = src_tex->read_aspect_mask; + image_memory_barrier.subresourceRange.baseMipLevel = p_base_mipmap; + image_memory_barrier.subresourceRange.levelCount = p_mipmaps; + image_memory_barrier.subresourceRange.baseArrayLayer = p_base_layer; + image_memory_barrier.subresourceRange.layerCount = p_layers; + + layout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, NULL, 0, NULL, 1, &image_memory_barrier); + } + + VkClearColorValue clear_color; + clear_color.float32[0] = p_color.r; + clear_color.float32[1] = p_color.g; + clear_color.float32[2] = p_color.b; + clear_color.float32[3] = p_color.a; + + VkImageSubresourceRange range; + range.aspectMask = src_tex->read_aspect_mask; + range.baseArrayLayer = p_base_layer; + range.layerCount = p_layers; + range.baseMipLevel = p_base_mipmap; + range.levelCount = p_mipmaps; + + vkCmdClearColorImage(command_buffer, src_tex->image, layout, &clear_color, 1, &range); + + if (src_tex->layout != VK_IMAGE_LAYOUT_GENERAL) { //storage may be in general state + + VkImageMemoryBarrier image_memory_barrier; + image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + image_memory_barrier.pNext = NULL; + image_memory_barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + image_memory_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + image_memory_barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + image_memory_barrier.newLayout = src_tex->layout; + + image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + image_memory_barrier.image = src_tex->image; + image_memory_barrier.subresourceRange.aspectMask = src_tex->read_aspect_mask; + image_memory_barrier.subresourceRange.baseMipLevel = p_base_mipmap; + image_memory_barrier.subresourceRange.levelCount = p_mipmaps; + image_memory_barrier.subresourceRange.baseArrayLayer = p_base_layer; + image_memory_barrier.subresourceRange.layerCount = p_layers; + + vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, NULL, 0, NULL, 1, &image_memory_barrier); + } + + return OK; +} + +bool RenderingDeviceVulkan::texture_is_format_supported_for_usage(DataFormat p_format, uint32_t p_usage) const { + ERR_FAIL_INDEX_V(p_format, DATA_FORMAT_MAX, false); + + _THREAD_SAFE_METHOD_ + + //validate that this image is supported for the intended use + VkFormatProperties properties; + vkGetPhysicalDeviceFormatProperties(context->get_physical_device(), vulkan_formats[p_format], &properties); + VkFormatFeatureFlags flags; + + if (p_usage & TEXTURE_USAGE_CPU_READ_BIT) { + flags = properties.linearTilingFeatures; + } else { + flags = properties.optimalTilingFeatures; + } + + if (p_usage & TEXTURE_USAGE_SAMPLING_BIT && !(flags & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT)) { + return false; + } + + if (p_usage & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT && !(flags & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT)) { + return false; + } + + if (p_usage & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT && !(flags & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)) { + return false; + } + + if (p_usage & TEXTURE_USAGE_STORAGE_BIT && !(flags & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT)) { + return false; + } + + if (p_usage & TEXTURE_USAGE_STORAGE_ATOMIC_BIT && !(flags & VK_FORMAT_FEATURE_STORAGE_IMAGE_ATOMIC_BIT)) { + return false; + } + + return true; +} + +/********************/ +/**** ATTACHMENT ****/ +/********************/ + +VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentFormat> &p_format, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, int *r_color_attachment_count) { + + Vector<VkAttachmentDescription> attachments; + Vector<VkAttachmentReference> color_references; + Vector<VkAttachmentReference> depth_stencil_references; + Vector<VkAttachmentReference> resolve_references; + + for (int i = 0; i < p_format.size(); i++) { + + VkAttachmentDescription description; + + description.flags = 0; + ERR_FAIL_INDEX_V(p_format[i].format, DATA_FORMAT_MAX, VK_NULL_HANDLE); + description.format = vulkan_formats[p_format[i].format]; + ERR_FAIL_INDEX_V(p_format[i].samples, TEXTURE_SAMPLES_MAX, VK_NULL_HANDLE); + description.samples = rasterization_sample_count[p_format[i].samples]; + //anything below does not really matter, as vulkan just ignores it when creating a pipeline + ERR_FAIL_COND_V_MSG(!(p_format[i].usage_flags & (TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | TEXTURE_USAGE_RESOLVE_ATTACHMENT_BIT)), VK_NULL_HANDLE, + "Texture format for index (" + itos(i) + ") requires an attachment (depth, stencil or resolve) bit set."); + + bool is_depth_stencil = p_format[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; + bool is_sampled = p_format[i].usage_flags & TEXTURE_USAGE_SAMPLING_BIT; + bool is_storage = p_format[i].usage_flags & TEXTURE_USAGE_STORAGE_BIT; + + switch (is_depth_stencil ? p_initial_depth_action : p_initial_color_action) { + + case INITIAL_ACTION_CLEAR: { + description.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + description.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; //don't care what is there + } break; + case INITIAL_ACTION_KEEP: { + if (p_format[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) { + description.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; + description.initialLayout = is_sampled ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); + description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + } else if (p_format[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { + description.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + description.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; //don't care what is there + description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + } else { + description.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + description.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; //don't care what is there + } + } break; + case INITIAL_ACTION_CONTINUE: { + if (p_format[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) { + description.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; + description.initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + } else if (p_format[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { + description.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; + description.initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; //don't care what is there + description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD; + } else { + description.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + description.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; //don't care what is there + } + } break; + default: { + ERR_FAIL_V(VK_NULL_HANDLE); //should never reach here + } + } + + switch (is_depth_stencil ? p_final_depth_action : p_final_color_action) { + case FINAL_ACTION_READ: { + + if (p_format[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) { + description.storeOp = VK_ATTACHMENT_STORE_OP_STORE; + description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + description.finalLayout = is_sampled ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); + } else if (p_format[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { + + description.storeOp = VK_ATTACHMENT_STORE_OP_STORE; + description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE; + description.finalLayout = is_sampled ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); + } else { + description.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + description.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; //don't care what is there + } + } break; + case FINAL_ACTION_DISCARD: { + if (p_format[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) { + description.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + description.finalLayout = is_sampled ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); + } else if (p_format[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { + + description.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + description.finalLayout = is_sampled ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); + } else { + description.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + description.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; //don't care what is there + } + } break; + case FINAL_ACTION_CONTINUE: { + if (p_format[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) { + description.storeOp = VK_ATTACHMENT_STORE_OP_STORE; + description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + description.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + } else if (p_format[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { + + description.storeOp = VK_ATTACHMENT_STORE_OP_STORE; + description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE; + description.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + } else { + description.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + description.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; //don't care what is there + } + + } break; + default: { + ERR_FAIL_V(VK_NULL_HANDLE); //should never reach here + } + } + + attachments.push_back(description); + + VkAttachmentReference reference; + reference.attachment = i; + + if (p_format[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) { + reference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + color_references.push_back(reference); + } else if (p_format[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { + reference.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + depth_stencil_references.push_back(reference); + } else if (p_format[i].usage_flags & TEXTURE_USAGE_RESOLVE_ATTACHMENT_BIT) { + reference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + resolve_references.push_back(reference); + } else { + ERR_FAIL_V_MSG(VK_NULL_HANDLE, "Texture index " + itos(i) + " is neither color, depth stencil or resolve so it can't be used as attachment."); + } + } + + ERR_FAIL_COND_V_MSG(depth_stencil_references.size() > 1, VK_NULL_HANDLE, + "Formats can only have one depth/stencil attachment, supplied (" + itos(depth_stencil_references.size()) + ")."); + + ERR_FAIL_COND_V_MSG(resolve_references.size() > 1, VK_NULL_HANDLE, + "Formats can only have one resolve attachment, supplied (" + itos(resolve_references.size()) + ")."); + + VkSubpassDescription subpass; + subpass.flags = 0; + subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; + subpass.inputAttachmentCount = 0; //unsupported for now + subpass.pInputAttachments = NULL; + subpass.colorAttachmentCount = color_references.size(); + subpass.pColorAttachments = color_references.ptr(); + subpass.pDepthStencilAttachment = depth_stencil_references.ptr(); + subpass.pResolveAttachments = resolve_references.ptr(); + subpass.preserveAttachmentCount = 0; + subpass.pPreserveAttachments = NULL; + + VkRenderPassCreateInfo render_pass_create_info; + render_pass_create_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; + render_pass_create_info.pNext = NULL; + render_pass_create_info.flags = 0; + render_pass_create_info.attachmentCount = attachments.size(); + render_pass_create_info.pAttachments = attachments.ptr(); + render_pass_create_info.subpassCount = 1; + render_pass_create_info.pSubpasses = &subpass; + render_pass_create_info.dependencyCount = 0; + render_pass_create_info.pDependencies = NULL; + + VkRenderPass render_pass; + VkResult res = vkCreateRenderPass(device, &render_pass_create_info, NULL, &render_pass); + ERR_FAIL_COND_V(res, VK_NULL_HANDLE); + + if (r_color_attachment_count) { + *r_color_attachment_count = color_references.size(); + } + return render_pass; +} + +RenderingDevice::FramebufferFormatID RenderingDeviceVulkan::framebuffer_format_create(const Vector<AttachmentFormat> &p_format) { + + _THREAD_SAFE_METHOD_ + + FramebufferFormatKey key; + key.attachments = p_format; + + const Map<FramebufferFormatKey, FramebufferFormatID>::Element *E = framebuffer_format_cache.find(key); + if (E) { + //exists, return + return E->get(); + } + + int color_references; + VkRenderPass render_pass = _render_pass_create(p_format, INITIAL_ACTION_CLEAR, FINAL_ACTION_DISCARD, INITIAL_ACTION_CLEAR, FINAL_ACTION_DISCARD, &color_references); //actions don't matter for this use case + + if (render_pass == VK_NULL_HANDLE) { //was likely invalid + return INVALID_ID; + } + FramebufferFormatID id = FramebufferFormatID(framebuffer_format_cache.size()) | (FramebufferFormatID(ID_TYPE_FRAMEBUFFER_FORMAT) << FramebufferFormatID(ID_BASE_SHIFT)); + + E = framebuffer_format_cache.insert(key, id); + FramebufferFormat fb_format; + fb_format.E = E; + fb_format.color_attachments = color_references; + fb_format.render_pass = render_pass; + fb_format.samples = p_format[0].samples; + framebuffer_formats[id] = fb_format; + return id; +} + +RenderingDevice::TextureSamples RenderingDeviceVulkan::framebuffer_format_get_texture_samples(FramebufferFormatID p_format) { + Map<FramebufferFormatID, FramebufferFormat>::Element *E = framebuffer_formats.find(p_format); + ERR_FAIL_COND_V(!E, TEXTURE_SAMPLES_1); + + return E->get().samples; +} + +/***********************/ +/**** RENDER TARGET ****/ +/***********************/ + +RID RenderingDeviceVulkan::framebuffer_create(const Vector<RID> &p_texture_attachments, FramebufferFormatID p_format_check) { + + _THREAD_SAFE_METHOD_ + + Vector<AttachmentFormat> attachments; + Size2i size; + + for (int i = 0; i < p_texture_attachments.size(); i++) { + Texture *texture = texture_owner.getornull(p_texture_attachments[i]); + ERR_FAIL_COND_V_MSG(!texture, RID(), "Texture index supplied for framebuffer (" + itos(i) + ") is not a valid texture."); + + if (i == 0) { + size.width = texture->width; + size.height = texture->height; + } else { + ERR_FAIL_COND_V_MSG((uint32_t)size.width != texture->width || (uint32_t)size.height != texture->height, RID(), + "All textures in a framebuffer should be the same size."); + } + + AttachmentFormat af; + af.format = texture->format; + af.samples = texture->samples; + af.usage_flags = texture->usage_flags; + attachments.push_back(af); + } + + FramebufferFormatID format_id = framebuffer_format_create(attachments); + if (format_id == INVALID_ID) { + return RID(); + } + + ERR_FAIL_COND_V_MSG(p_format_check != INVALID_ID && format_id != p_format_check, RID(), + "The format used to check this framebuffer differs from the intended framebuffer format."); + + Framebuffer framebuffer; + framebuffer.format_id = format_id; + framebuffer.texture_ids = p_texture_attachments; + framebuffer.size = size; + + RID id = framebuffer_owner.make_rid(framebuffer); + + for (int i = 0; i < p_texture_attachments.size(); i++) { + _add_dependency(id, p_texture_attachments[i]); + } + + return id; +} + +RenderingDevice::FramebufferFormatID RenderingDeviceVulkan::framebuffer_get_format(RID p_framebuffer) { + + _THREAD_SAFE_METHOD_ + + Framebuffer *framebuffer = framebuffer_owner.getornull(p_framebuffer); + ERR_FAIL_COND_V(!framebuffer, INVALID_ID); + + return framebuffer->format_id; +} + +/*****************/ +/**** SAMPLER ****/ +/*****************/ + +RID RenderingDeviceVulkan::sampler_create(const SamplerState &p_state) { + + _THREAD_SAFE_METHOD_ + + VkSamplerCreateInfo sampler_create_info; + sampler_create_info.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; + sampler_create_info.pNext = NULL; + sampler_create_info.flags = 0; + sampler_create_info.magFilter = p_state.mag_filter == SAMPLER_FILTER_LINEAR ? VK_FILTER_LINEAR : VK_FILTER_NEAREST; + sampler_create_info.minFilter = p_state.min_filter == SAMPLER_FILTER_LINEAR ? VK_FILTER_LINEAR : VK_FILTER_NEAREST; + sampler_create_info.mipmapMode = p_state.mip_filter == SAMPLER_FILTER_LINEAR ? VK_SAMPLER_MIPMAP_MODE_LINEAR : VK_SAMPLER_MIPMAP_MODE_NEAREST; + + ERR_FAIL_INDEX_V(p_state.repeat_u, SAMPLER_REPEAT_MODE_MAX, RID()); + sampler_create_info.addressModeU = address_modes[p_state.repeat_u]; + ERR_FAIL_INDEX_V(p_state.repeat_v, SAMPLER_REPEAT_MODE_MAX, RID()); + sampler_create_info.addressModeV = address_modes[p_state.repeat_v]; + ERR_FAIL_INDEX_V(p_state.repeat_w, SAMPLER_REPEAT_MODE_MAX, RID()); + sampler_create_info.addressModeW = address_modes[p_state.repeat_w]; + + sampler_create_info.mipLodBias = p_state.lod_bias; + sampler_create_info.anisotropyEnable = p_state.use_anisotropy; + sampler_create_info.maxAnisotropy = p_state.anisotropy_max; + sampler_create_info.compareEnable = p_state.enable_compare; + + ERR_FAIL_INDEX_V(p_state.compare_op, COMPARE_OP_MAX, RID()); + sampler_create_info.compareOp = compare_operators[p_state.compare_op]; + + sampler_create_info.minLod = p_state.min_lod; + sampler_create_info.maxLod = p_state.max_lod; + + ERR_FAIL_INDEX_V(p_state.border_color, SAMPLER_BORDER_COLOR_MAX, RID()); + sampler_create_info.borderColor = sampler_border_colors[p_state.border_color]; + + sampler_create_info.unnormalizedCoordinates = p_state.unnormalized_uvw; + + VkSampler sampler; + VkResult res = vkCreateSampler(device, &sampler_create_info, NULL, &sampler); + ERR_FAIL_COND_V(res, RID()); + + return sampler_owner.make_rid(sampler); +} + +/**********************/ +/**** VERTEX ARRAY ****/ +/**********************/ + +RID RenderingDeviceVulkan::vertex_buffer_create(uint32_t p_size_bytes, const PoolVector<uint8_t> &p_data) { + + _THREAD_SAFE_METHOD_ + + ERR_FAIL_COND_V(p_data.size() && (uint32_t)p_data.size() != p_size_bytes, RID()); + + Buffer buffer; + _buffer_allocate(&buffer, p_size_bytes, VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VMA_MEMORY_USAGE_GPU_ONLY); + if (p_data.size()) { + uint64_t data_size = p_data.size(); + PoolVector<uint8_t>::Read r = p_data.read(); + _buffer_update(&buffer, 0, r.ptr(), data_size); + _buffer_memory_barrier(buffer.buffer, 0, data_size, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT, false); + } + + return vertex_buffer_owner.make_rid(buffer); +} + +// Internally reference counted, this ID is warranted to be unique for the same description, but needs to be freed as many times as it was allocated +RenderingDevice::VertexFormatID RenderingDeviceVulkan::vertex_format_create(const Vector<VertexDescription> &p_vertex_formats) { + + _THREAD_SAFE_METHOD_ + + VertexDescriptionKey key; + key.vertex_formats = p_vertex_formats; + + VertexFormatID *idptr = vertex_format_cache.getptr(key); + if (idptr) { + return *idptr; + } + + //does not exist, create one and cache it + VertexDescriptionCache vdcache; + vdcache.bindings = memnew_arr(VkVertexInputBindingDescription, p_vertex_formats.size()); + vdcache.attributes = memnew_arr(VkVertexInputAttributeDescription, p_vertex_formats.size()); + + Set<int> used_locations; + for (int i = 0; i < p_vertex_formats.size(); i++) { + ERR_CONTINUE(p_vertex_formats[i].format >= DATA_FORMAT_MAX); + ERR_FAIL_COND_V(used_locations.has(p_vertex_formats[i].location), INVALID_ID); + + ERR_FAIL_COND_V_MSG(get_format_vertex_size(p_vertex_formats[i].format) == 0, INVALID_ID, + "Data format for attachment (" + itos(i) + ") is not valid for a vertex array."); + + vdcache.bindings[i].binding = i; + vdcache.bindings[i].stride = p_vertex_formats[i].stride; + vdcache.bindings[i].inputRate = p_vertex_formats[i].frequency == VERTEX_FREQUENCY_INSTANCE ? VK_VERTEX_INPUT_RATE_INSTANCE : VK_VERTEX_INPUT_RATE_VERTEX; + vdcache.attributes[i].binding = i; + vdcache.attributes[i].location = p_vertex_formats[i].location; + vdcache.attributes[i].format = vulkan_formats[p_vertex_formats[i].format]; + vdcache.attributes[i].offset = p_vertex_formats[i].offset; + used_locations.insert(p_vertex_formats[i].location); + } + + vdcache.create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; + vdcache.create_info.pNext = NULL; + vdcache.create_info.flags = 0; + + vdcache.create_info.vertexAttributeDescriptionCount = p_vertex_formats.size(); + vdcache.create_info.pVertexAttributeDescriptions = vdcache.attributes; + + vdcache.create_info.vertexBindingDescriptionCount = p_vertex_formats.size(); + vdcache.create_info.pVertexBindingDescriptions = vdcache.bindings; + vdcache.vertex_formats = p_vertex_formats; + + VertexFormatID id = VertexFormatID(vertex_format_cache.size()) | (VertexFormatID(ID_TYPE_VERTEX_FORMAT) << ID_BASE_SHIFT); + vertex_format_cache[key] = id; + vertex_formats[id] = vdcache; + return id; +} + +RID RenderingDeviceVulkan::vertex_array_create(uint32_t p_vertex_count, VertexFormatID p_vertex_format, const Vector<RID> &p_src_buffers) { + + _THREAD_SAFE_METHOD_ + + ERR_FAIL_COND_V(!vertex_formats.has(p_vertex_format), RID()); + const VertexDescriptionCache &vd = vertex_formats[p_vertex_format]; + + ERR_FAIL_COND_V(vd.vertex_formats.size() != p_src_buffers.size(), RID()); + + for (int i = 0; i < p_src_buffers.size(); i++) { + ERR_FAIL_COND_V(!vertex_buffer_owner.owns(p_src_buffers[i]), RID()); + } + + VertexArray vertex_array; + + vertex_array.vertex_count = p_vertex_count; + vertex_array.description = p_vertex_format; + vertex_array.max_instances_allowed = 0xFFFFFFFF; //by default as many as you want + for (int i = 0; i < p_src_buffers.size(); i++) { + Buffer *buffer = vertex_buffer_owner.getornull(p_src_buffers[i]); + + //validate with buffer + { + const VertexDescription &atf = vd.vertex_formats[i]; + + uint32_t element_size = get_format_vertex_size(atf.format); + ERR_FAIL_COND_V(element_size == 0, RID()); //should never happens since this was prevalidated + + if (atf.frequency == VERTEX_FREQUENCY_VERTEX) { + //validate size for regular drawing + uint64_t total_size = uint64_t(atf.stride) * (p_vertex_count - 1) + atf.offset + element_size; + ERR_FAIL_COND_V_MSG(total_size > buffer->size, RID(), + "Attachment (" + itos(i) + ") will read past the end of the buffer."); + + } else { + //validate size for instances drawing + uint64_t available = buffer->size - atf.offset; + ERR_FAIL_COND_V_MSG(available < element_size, RID(), + "Attachment (" + itos(i) + ") uses instancing, but it's just too small."); + + uint32_t instances_allowed = available / atf.stride; + vertex_array.max_instances_allowed = MIN(instances_allowed, vertex_array.max_instances_allowed); + } + } + + vertex_array.buffers.push_back(buffer->buffer); + vertex_array.offsets.push_back(0); //offset unused, but passing anyway + } + + RID id = vertex_array_owner.make_rid(vertex_array); + for (int i = 0; i < p_src_buffers.size(); i++) { + _add_dependency(id, p_src_buffers[i]); + } + + return id; +} + +RID RenderingDeviceVulkan::index_buffer_create(uint32_t p_index_count, IndexBufferFormat p_format, const PoolVector<uint8_t> &p_data, bool p_use_restart_indices) { + + _THREAD_SAFE_METHOD_ + + ERR_FAIL_COND_V(p_index_count == 0, RID()); + + IndexBuffer index_buffer; + index_buffer.index_type = (p_format == INDEX_BUFFER_FORMAT_UINT16) ? VK_INDEX_TYPE_UINT16 : VK_INDEX_TYPE_UINT32; + index_buffer.supports_restart_indices = p_use_restart_indices; + index_buffer.index_count = p_index_count; + uint32_t size_bytes = p_index_count * ((p_format == INDEX_BUFFER_FORMAT_UINT16) ? 2 : 4); +#ifdef DEBUG_ENABLED + if (p_data.size()) { + index_buffer.max_index = 0; + ERR_FAIL_COND_V_MSG((uint32_t)p_data.size() != size_bytes, RID(), + "Default index buffer initializer array size (" + itos(p_data.size()) + ") does not match format required size (" + itos(size_bytes) + ")."); + PoolVector<uint8_t>::Read r = p_data.read(); + if (p_format == INDEX_BUFFER_FORMAT_UINT16) { + const uint16_t *index16 = (const uint16_t *)r.ptr(); + for (uint32_t i = 0; i < p_index_count; i++) { + if (p_use_restart_indices && index16[i] == 0xFFFF) { + continue; //restart index, ingnore + } + index_buffer.max_index = MAX(index16[i], index_buffer.max_index); + } + } else { + const uint32_t *index32 = (const uint32_t *)r.ptr(); + for (uint32_t i = 0; i < p_index_count; i++) { + if (p_use_restart_indices && index32[i] == 0xFFFFFFFF) { + continue; //restart index, ingnore + } + index_buffer.max_index = MAX(index32[i], index_buffer.max_index); + } + } + } else { + index_buffer.max_index = 0xFFFFFFFF; + } +#else + index_buffer.max_index = 0xFFFFFFFF; +#endif + _buffer_allocate(&index_buffer, size_bytes, VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VMA_MEMORY_USAGE_GPU_ONLY); + if (p_data.size()) { + uint64_t data_size = p_data.size(); + PoolVector<uint8_t>::Read r = p_data.read(); + _buffer_update(&index_buffer, 0, r.ptr(), data_size); + _buffer_memory_barrier(index_buffer.buffer, 0, data_size, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_INDEX_READ_BIT, false); + } + return index_buffer_owner.make_rid(index_buffer); +} + +RID RenderingDeviceVulkan::index_array_create(RID p_index_buffer, uint32_t p_index_offset, uint32_t p_index_count) { + + _THREAD_SAFE_METHOD_ + + ERR_FAIL_COND_V(!index_buffer_owner.owns(p_index_buffer), RID()); + + IndexBuffer *index_buffer = index_buffer_owner.getornull(p_index_buffer); + + ERR_FAIL_COND_V(p_index_count == 0, RID()); + ERR_FAIL_COND_V(p_index_offset + p_index_count > index_buffer->index_count, RID()); + + IndexArray index_array; + index_array.max_index = index_buffer->max_index; + index_array.buffer = index_buffer->buffer; + index_array.offset = p_index_offset; + index_array.indices = p_index_count; + index_array.index_type = index_buffer->index_type; + index_array.supports_restart_indices = index_buffer->supports_restart_indices; + + RID id = index_array_owner.make_rid(index_array); + _add_dependency(id, p_index_buffer); + return id; +} + +/****************/ +/**** SHADER ****/ +/****************/ + +static const char *shader_stage_names[RenderingDevice::SHADER_STAGE_MAX] = { + "Vertex", + "Fragment", + "TesselationControl", + "TesselationEvaluation", + "Compute" +}; + +static const char *shader_uniform_names[RenderingDevice::UNIFORM_TYPE_MAX] = { + "Sampler", "CombinedSampler", "Texture", "Image", "TextureBuffer", "SamplerTextureBuffer", "ImageBuffer", "UniformBuffer", "StorageBuffer", "InputAttachment" +}; + +static VkShaderStageFlagBits shader_stage_masks[RenderingDevice::SHADER_STAGE_MAX] = { + VK_SHADER_STAGE_VERTEX_BIT, + VK_SHADER_STAGE_FRAGMENT_BIT, + VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, + VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, + VK_SHADER_STAGE_COMPUTE_BIT, +}; + +String RenderingDeviceVulkan::_shader_uniform_debug(RID p_shader, int p_set) { + String ret; + const Shader *shader = shader_owner.getornull(p_shader); + ERR_FAIL_COND_V(!shader, String()); + for (int i = 0; i < shader->sets.size(); i++) { + if (p_set >= 0 && i != p_set) { + continue; + } + for (int j = 0; j < shader->sets[i].uniform_info.size(); j++) { + const UniformInfo &ui = shader->sets[i].uniform_info[j]; + if (ret != String()) { + ret += "\n"; + } + ret += "Set: " + itos(i) + " Binding: " + itos(ui.binding) + " Type: " + shader_uniform_names[ui.type] + " Length: " + itos(ui.length); + } + } + return ret; +} +#if 0 +bool RenderingDeviceVulkan::_uniform_add_binding(Vector<Vector<VkDescriptorSetLayoutBinding> > &bindings, Vector<Vector<UniformInfo> > &uniform_infos, const glslang::TObjectReflection &reflection, RenderingDevice::ShaderStage p_stage, Shader::PushConstant &push_constant, String *r_error) { + + VkDescriptorSetLayoutBinding layout_binding; + UniformInfo info; + + switch (reflection.getType()->getBasicType()) { + case glslang::EbtSampler: { + + //print_line("DEBUG: IsSampler"); + if (reflection.getType()->getSampler().dim == glslang::EsdBuffer) { + //texture buffers + if (reflection.getType()->getSampler().isCombined()) { + layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER; + info.type = UNIFORM_TYPE_SAMPLER_WITH_TEXTURE_BUFFER; + //print_line("DEBUG: SAMPLER: texel combined"); + } else if (reflection.getType()->getSampler().isTexture()) { + layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER; + info.type = UNIFORM_TYPE_TEXTURE_BUFFER; + //print_line("DEBUG: SAMPLER: texel alone"); + } else if (reflection.getType()->getSampler().isImage()) { + layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER; + info.type = UNIFORM_TYPE_IMAGE_BUFFER; + //print_line("DEBUG: SAMPLER: texel buffer"); + } else { + if (r_error) { + *r_error = "On shader stage '" + String(shader_stage_names[p_stage]) + "', uniform '" + reflection.name.c_str() + "' is of unsupported buffer type."; + } + return false; + } + } else if (reflection.getType()->getSampler().isCombined()) { + layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + info.type = UNIFORM_TYPE_SAMPLER_WITH_TEXTURE; + //print_line("DEBUG: SAMPLER: combined"); + } else if (reflection.getType()->getSampler().isPureSampler()) { + layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER; + info.type = UNIFORM_TYPE_SAMPLER; + //print_line("DEBUG: SAMPLER: sampler"); + } else if (reflection.getType()->getSampler().isTexture()) { + layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; + info.type = UNIFORM_TYPE_TEXTURE; + //print_line("DEBUG: SAMPLER: image"); + } else if (reflection.getType()->getSampler().isImage()) { + layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; + info.type = UNIFORM_TYPE_IMAGE; + //print_line("DEBUG: SAMPLER: storage image"); + } else { + //print_line("DEBUG: sampler unknown"); + if (r_error) { + *r_error = "On shader stage '" + String(shader_stage_names[p_stage]) + "', uniform '" + reflection.name.c_str() + "' is of unsupported sampler type."; + } + return false; + } + + if (reflection.getType()->isArray()) { + layout_binding.descriptorCount = reflection.getType()->getArraySizes()->getCumulativeSize(); + //print_line("DEBUG: array of size: " + itos(layout_binding.descriptorCount)); + } else { + layout_binding.descriptorCount = 1; + } + + info.length = layout_binding.descriptorCount; + + } break; + /*case glslang::EbtStruct: { + print_line("DEBUG: Struct"); + + } break;*/ + case glslang::EbtBlock: { + //print_line("DEBUG: Block"); + if (reflection.getType()->getQualifier().storage == glslang::EvqUniform) { + if (reflection.getType()->getQualifier().layoutPushConstant) { + uint32_t len = reflection.size; + if (push_constant.push_constant_size != 0 && push_constant.push_constant_size != len) { + *r_error = "On shader stage '" + String(shader_stage_names[p_stage]) + "', uniform '" + reflection.name.c_str() + "' push constants for different stages should all be the same size."; + return false; + } + push_constant.push_constant_size = len; + push_constant.push_constants_vk_stage |= shader_stage_masks[p_stage]; + return true; + } + //print_line("DEBUG: Uniform buffer"); + layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + info.type = UNIFORM_TYPE_UNIFORM_BUFFER; + } else if (reflection.getType()->getQualifier().storage == glslang::EvqBuffer) { + layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; + info.type = UNIFORM_TYPE_STORAGE_BUFFER; + //print_line("DEBUG: Storage buffer"); + } else { + if (r_error) { + *r_error = "On shader stage '" + String(shader_stage_names[p_stage]) + "', uniform '" + reflection.name.c_str() + "' is of unsupported block type: (" + itos(reflection.getType()->getQualifier().storage) + ")."; + } + return false; + } + + if (reflection.getType()->isArray()) { + layout_binding.descriptorCount = reflection.getType()->getArraySizes()->getCumulativeSize(); + //print_line("DEBUG: array of size: " + itos(layout_binding.descriptorCount)); + } else { + layout_binding.descriptorCount = 1; + } + + info.length = reflection.size; + + } break; + /*case glslang::EbtReference: { + + } break;*/ + /*case glslang::EbtAtomicUint: { + + } break;*/ + default: { + + if (reflection.getType()->getQualifier().hasOffset() || reflection.name.find(".") != std::string::npos) { + //member of uniform block? + return true; + } + + if (r_error) { + *r_error = "On shader stage '" + String(shader_stage_names[p_stage]) + "', uniform '" + reflection.name.c_str() + "' unsupported uniform type."; + } + return false; + } + } + + if (!reflection.getType()->getQualifier().hasBinding()) { + if (r_error) { + *r_error = "On shader stage '" + String(shader_stage_names[p_stage]) + "', uniform '" + reflection.name.c_str() + "' lacks a binding number."; + } + return false; + } + + uint32_t set = reflection.getType()->getQualifier().hasSet() ? reflection.getType()->getQualifier().layoutSet : 0; + + if (set >= MAX_UNIFORM_SETS) { + if (r_error) { + *r_error = "On shader stage '" + String(shader_stage_names[p_stage]) + "', uniform '" + reflection.name.c_str() + "' uses a set (" + itos(set) + ") index larger than what is supported (" + itos(MAX_UNIFORM_SETS) + ")."; + } + return false; + } + + if (set >= limits.maxBoundDescriptorSets) { + if (r_error) { + *r_error = "On shader stage '" + String(shader_stage_names[p_stage]) + "', uniform '" + reflection.name.c_str() + "' uses a set (" + itos(set) + ") index larger than what is supported by the hardware (" + itos(limits.maxBoundDescriptorSets) + ")."; + } + return false; + } + + uint32_t binding = reflection.getType()->getQualifier().layoutBinding; + + if (set < (uint32_t)bindings.size()) { + //check if this already exists + for (int i = 0; i < bindings[set].size(); i++) { + if (bindings[set][i].binding == binding) { + //already exists, verify that it's the same type + if (bindings[set][i].descriptorType != layout_binding.descriptorType) { + if (r_error) { + *r_error = "On shader stage '" + String(shader_stage_names[p_stage]) + "', uniform '" + reflection.name.c_str() + "' trying to re-use location for set=" + itos(set) + ", binding=" + itos(binding) + " with different uniform type."; + } + return false; + } + + //also, verify that it's the same size + if (bindings[set][i].descriptorCount != layout_binding.descriptorCount || uniform_infos[set][i].length != info.length) { + if (r_error) { + *r_error = "On shader stage '" + String(shader_stage_names[p_stage]) + "', uniform '" + reflection.name.c_str() + "' trying to re-use location for set=" + itos(set) + ", binding=" + itos(binding) + " with different uniform size."; + } + return false; + } + + //just append stage mask and return + bindings.write[set].write[i].stageFlags |= shader_stage_masks[p_stage]; + uniform_infos.write[set].write[i].stages |= 1 << p_stage; + return true; + } + } + } + layout_binding.binding = binding; + layout_binding.stageFlags = shader_stage_masks[p_stage]; + layout_binding.pImmutableSamplers = NULL; //no support for this yet + + info.stages = 1 << p_stage; + info.binding = binding; + + if (set >= (uint32_t)bindings.size()) { + bindings.resize(set + 1); + uniform_infos.resize(set + 1); + } +#if 0 + print_line("stage: " + String(shader_stage_names[p_stage]) + " set: " + itos(set) + " binding: " + itos(info.binding) + " type:" + shader_uniform_names[info.type] + " length: " + itos(info.length)); +#endif + bindings.write[set].push_back(layout_binding); + uniform_infos.write[set].push_back(info); + + return true; +} +#endif + +RID RenderingDeviceVulkan::shader_create(const Vector<ShaderStageData> &p_stages) { + + //descriptor layouts + Vector<Vector<VkDescriptorSetLayoutBinding> > set_bindings; + Vector<Vector<UniformInfo> > uniform_info; + Shader::PushConstant push_constant; + push_constant.push_constant_size = 0; + push_constant.push_constants_vk_stage = 0; + + uint32_t vertex_input_mask = 0; + + uint32_t fragment_outputs = 0; + + uint32_t stages_processed = 0; + + bool is_compute = false; + + for (int i = 0; i < p_stages.size(); i++) { + + if (p_stages[i].shader_stage == SHADER_STAGE_COMPUTE) { + is_compute = true; + ERR_FAIL_COND_V_MSG(p_stages.size() != 1, RID(), + "Compute shaders can only receive one stage, dedicated to compute."); + } + ERR_FAIL_COND_V_MSG(stages_processed & (1 << p_stages[i].shader_stage), RID(), + "Stage " + String(shader_stage_names[p_stages[i].shader_stage]) + " submitted more than once."); + + { + SpvReflectShaderModule module; + PoolVector<uint8_t>::Read spirv = p_stages[i].spir_v.read(); + SpvReflectResult result = spvReflectCreateShaderModule(p_stages[i].spir_v.size(), spirv.ptr(), &module); + ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, RID(), + "Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_stages[i].shader_stage]) + "' failed parsing shader."); + + uint32_t binding_count = 0; + result = spvReflectEnumerateDescriptorBindings(&module, &binding_count, NULL); + ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, RID(), + "Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_stages[i].shader_stage]) + "' failed enumerating descriptor bindings."); + + uint32_t stage = p_stages[i].shader_stage; + + if (binding_count > 0) { + + //Parse bindings + + Vector<SpvReflectDescriptorBinding *> bindings; + bindings.resize(binding_count); + result = spvReflectEnumerateDescriptorBindings(&module, &binding_count, bindings.ptrw()); + + ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, RID(), + "Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_stages[i].shader_stage]) + "' failed getting descriptor bindings."); + + for (uint32_t j = 0; j < binding_count; j++) { + const SpvReflectDescriptorBinding &binding = *bindings[j]; + + VkDescriptorSetLayoutBinding layout_binding; + UniformInfo info; + + bool need_array_dimensions = false; + bool need_block_size = false; + + switch (binding.descriptor_type) { + case SPV_REFLECT_DESCRIPTOR_TYPE_SAMPLER: { + layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER; + info.type = UNIFORM_TYPE_SAMPLER; + need_array_dimensions = true; + } break; + case SPV_REFLECT_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: { + layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + info.type = UNIFORM_TYPE_SAMPLER_WITH_TEXTURE; + need_array_dimensions = true; + } break; + case SPV_REFLECT_DESCRIPTOR_TYPE_SAMPLED_IMAGE: { + layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; + info.type = UNIFORM_TYPE_TEXTURE; + need_array_dimensions = true; + } break; + case SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_IMAGE: { + layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; + info.type = UNIFORM_TYPE_IMAGE; + need_array_dimensions = true; + } break; + case SPV_REFLECT_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER: { + layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER; + info.type = UNIFORM_TYPE_TEXTURE_BUFFER; + need_array_dimensions = true; + } break; + case SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER: { + layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER; + info.type = UNIFORM_TYPE_IMAGE_BUFFER; + need_array_dimensions = true; + } break; + case SPV_REFLECT_DESCRIPTOR_TYPE_UNIFORM_BUFFER: { + layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + info.type = UNIFORM_TYPE_UNIFORM_BUFFER; + need_block_size = true; + } break; + case SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_BUFFER: { + layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; + info.type = UNIFORM_TYPE_STORAGE_BUFFER; + need_block_size = true; + } break; + case SPV_REFLECT_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC: { + ERR_PRINT("Dynamic uniform buffer not supported."); + continue; + } break; + case SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC: { + ERR_PRINT("Dynamic storage buffer not supported."); + continue; + } break; + case SPV_REFLECT_DESCRIPTOR_TYPE_INPUT_ATTACHMENT: { + layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT; + info.type = UNIFORM_TYPE_INPUT_ATTACHMENT; + } break; + } + + if (need_array_dimensions) { + if (binding.array.dims_count == 0) { + info.length = 1; + } else { + for (uint32_t k = 0; k < binding.array.dims_count; k++) { + if (k == 0) { + info.length = binding.array.dims[0]; + } else { + info.length *= binding.array.dims[k]; + } + } + } + + layout_binding.descriptorCount = info.length; + + } else if (need_block_size) { + info.length = binding.block.size; + layout_binding.descriptorCount = 1; + } else { + info.length = 0; + layout_binding.descriptorCount = 1; + } + + info.binding = binding.binding; + uint32_t set = binding.set; + + //print_line("Stage: " + String(shader_stage_names[stage]) + " set=" + itos(set) + " binding=" + itos(info.binding) + " type=" + shader_uniform_names[info.type] + " length=" + itos(info.length)); + + ERR_FAIL_COND_V_MSG(set >= MAX_UNIFORM_SETS, RID(), + "On shader stage '" + String(shader_stage_names[stage]) + "', uniform '" + binding.name + "' uses a set (" + itos(set) + ") index larger than what is supported (" + itos(MAX_UNIFORM_SETS) + ")."); + + ERR_FAIL_COND_V_MSG(set >= limits.maxBoundDescriptorSets, RID(), + "On shader stage '" + String(shader_stage_names[stage]) + "', uniform '" + binding.name + "' uses a set (" + itos(set) + ") index larger than what is supported by the hardware (" + itos(limits.maxBoundDescriptorSets) + ")."); + + if (set < (uint32_t)set_bindings.size()) { + //check if this already exists + bool exists = false; + for (int k = 0; k < set_bindings[set].size(); k++) { + if (set_bindings[set][k].binding == (uint32_t)info.binding) { + //already exists, verify that it's the same type + ERR_FAIL_COND_V_MSG(set_bindings[set][k].descriptorType != layout_binding.descriptorType, RID(), + "On shader stage '" + String(shader_stage_names[stage]) + "', uniform '" + binding.name + "' trying to re-use location for set=" + itos(set) + ", binding=" + itos(info.binding) + " with different uniform type."); + + //also, verify that it's the same size + ERR_FAIL_COND_V_MSG(set_bindings[set][k].descriptorCount != layout_binding.descriptorCount || uniform_info[set][k].length != info.length, RID(), + "On shader stage '" + String(shader_stage_names[stage]) + "', uniform '" + binding.name + "' trying to re-use location for set=" + itos(set) + ", binding=" + itos(info.binding) + " with different uniform size."); + + //just append stage mask and return + set_bindings.write[set].write[k].stageFlags |= shader_stage_masks[stage]; + uniform_info.write[set].write[k].stages |= 1 << stage; + exists = true; + } + } + + if (exists) { + continue; //merged + } + } + + layout_binding.binding = info.binding; + layout_binding.stageFlags = shader_stage_masks[stage]; + layout_binding.pImmutableSamplers = NULL; //no support for this yet + + info.stages = 1 << stage; + info.binding = info.binding; + + if (set >= (uint32_t)set_bindings.size()) { + set_bindings.resize(set + 1); + uniform_info.resize(set + 1); + } + + set_bindings.write[set].push_back(layout_binding); + uniform_info.write[set].push_back(info); + } + } + + if (stage == SHADER_STAGE_VERTEX) { + + uint32_t iv_count = 0; + result = spvReflectEnumerateInputVariables(&module, &iv_count, NULL); + ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, RID(), + "Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_stages[i].shader_stage]) + "' failed enumerating input variables."); + + if (iv_count) { + Vector<SpvReflectInterfaceVariable *> input_vars; + input_vars.resize(iv_count); + + result = spvReflectEnumerateInputVariables(&module, &iv_count, input_vars.ptrw()); + ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, RID(), + "Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_stages[i].shader_stage]) + "' failed obtaining input variables."); + + for (uint32_t j = 0; j < iv_count; j++) { + if (input_vars[j] && input_vars[j]->decoration_flags == 0) { //regular input + vertex_input_mask |= (1 << uint32_t(input_vars[j]->location)); + } + } + } + } + + if (stage == SHADER_STAGE_FRAGMENT) { + + uint32_t ov_count = 0; + result = spvReflectEnumerateOutputVariables(&module, &ov_count, NULL); + ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, RID(), + "Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_stages[i].shader_stage]) + "' failed enumerating output variables."); + + if (ov_count) { + Vector<SpvReflectInterfaceVariable *> output_vars; + output_vars.resize(ov_count); + + result = spvReflectEnumerateOutputVariables(&module, &ov_count, output_vars.ptrw()); + ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, RID(), + "Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_stages[i].shader_stage]) + "' failed obtaining output variables."); + + for (uint32_t j = 0; j < ov_count; j++) { + if (output_vars[j]) { + fragment_outputs = MAX(fragment_outputs, output_vars[j]->location + 1); + } + } + } + } + uint32_t pc_count = 0; + result = spvReflectEnumeratePushConstantBlocks(&module, &pc_count, NULL); + ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, RID(), + "Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_stages[i].shader_stage]) + "' failed enumerating push constants."); + + if (pc_count) { + ERR_FAIL_COND_V_MSG(pc_count > 1, RID(), + "Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_stages[i].shader_stage]) + "': Only one push constant is supported, which should be the same across shader stages."); + + Vector<SpvReflectBlockVariable *> pconstants; + pconstants.resize(pc_count); + result = spvReflectEnumeratePushConstantBlocks(&module, &pc_count, pconstants.ptrw()); + ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, RID(), + "Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_stages[i].shader_stage]) + "' failed obtaining push constants."); +#if 0 + if (pconstants[0] == NULL) { + FileAccess *f = FileAccess::open("res://popo.spv", FileAccess::WRITE); + f->store_buffer((const uint8_t *)&SpirV[0], SpirV.size() * sizeof(uint32_t)); + memdelete(f); + } +#endif + + ERR_FAIL_COND_V_MSG(push_constant.push_constant_size && push_constant.push_constant_size != pconstants[0]->size, RID(), + "Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_stages[i].shader_stage]) + "': Push constant block must be the same across shader stages."); + + push_constant.push_constant_size = pconstants[0]->size; + push_constant.push_constants_vk_stage |= shader_stage_masks[stage]; + + //print_line("Stage: " + String(shader_stage_names[stage]) + " push constant of size=" + itos(push_constant.push_constant_size)); + } + + // Destroy the reflection data when no longer required. + spvReflectDestroyShaderModule(&module); + } + + stages_processed |= (1 << p_stages[i].shader_stage); + } + + //all good, let's create modules + + _THREAD_SAFE_METHOD_ + + Shader shader; + + shader.vertex_input_mask = vertex_input_mask; + shader.fragment_outputs = fragment_outputs; + shader.push_constant = push_constant; + shader.is_compute = is_compute; + + String error_text; + + bool success = true; + for (int i = 0; i < p_stages.size(); i++) { + VkShaderModuleCreateInfo shader_module_create_info; + shader_module_create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; + shader_module_create_info.pNext = NULL; + shader_module_create_info.flags = 0; + shader_module_create_info.codeSize = p_stages[i].spir_v.size(); + PoolVector<uint8_t>::Read r = p_stages[i].spir_v.read(); + + shader_module_create_info.pCode = (const uint32_t *)r.ptr(); + + VkShaderModule module; + VkResult res = vkCreateShaderModule(device, &shader_module_create_info, NULL, &module); + if (res) { + success = false; + error_text = "Error creating shader module for stage: " + String(shader_stage_names[p_stages[i].shader_stage]); + break; + } + + const VkShaderStageFlagBits shader_stage_bits[SHADER_STAGE_MAX] = { + VK_SHADER_STAGE_VERTEX_BIT, + VK_SHADER_STAGE_FRAGMENT_BIT, + VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, + VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, + VK_SHADER_STAGE_COMPUTE_BIT, + }; + + VkPipelineShaderStageCreateInfo shader_stage; + shader_stage.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + shader_stage.pNext = NULL; + shader_stage.flags = 0; + shader_stage.stage = shader_stage_bits[p_stages[i].shader_stage]; + shader_stage.module = module; + shader_stage.pName = "main"; + shader_stage.pSpecializationInfo = NULL; + + shader.pipeline_stages.push_back(shader_stage); + } + //proceed to create descriptor sets + + if (success) { + + for (int i = 0; i < set_bindings.size(); i++) { + + //empty ones are fine if they were not used according to spec (binding count will be 0) + VkDescriptorSetLayoutCreateInfo layout_create_info; + layout_create_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; + layout_create_info.pNext = NULL; + layout_create_info.flags = 0; + layout_create_info.bindingCount = set_bindings[i].size(); + layout_create_info.pBindings = set_bindings[i].ptr(); + + VkDescriptorSetLayout layout; + VkResult res = vkCreateDescriptorSetLayout(device, &layout_create_info, NULL, &layout); + if (res) { + error_text = "Error creating descriptor set layout for set " + itos(i); + success = false; + break; + } + + Shader::Set set; + set.descriptor_set_layout = layout; + set.uniform_info = uniform_info[i]; + //sort and hash + set.uniform_info.sort(); + + uint32_t format = 0; //no format, default + + if (set.uniform_info.size()) { + //has data, needs an actual format; + UniformSetFormat usformat; + usformat.uniform_info = set.uniform_info; + Map<UniformSetFormat, uint32_t>::Element *E = uniform_set_format_cache.find(usformat); + if (E) { + format = E->get(); + } else { + format = uniform_set_format_cache.size() + 1; + uniform_set_format_cache.insert(usformat, format); + } + } + + shader.sets.push_back(set); + shader.set_formats.push_back(format); + } + } + + if (success) { + //create pipeline layout + VkPipelineLayoutCreateInfo pipeline_layout_create_info; + pipeline_layout_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; + pipeline_layout_create_info.pNext = NULL; + pipeline_layout_create_info.flags = 0; + pipeline_layout_create_info.setLayoutCount = shader.sets.size(); + + Vector<VkDescriptorSetLayout> layouts; + layouts.resize(shader.sets.size()); + + for (int i = 0; i < layouts.size(); i++) { + layouts.write[i] = shader.sets[i].descriptor_set_layout; + } + + pipeline_layout_create_info.pSetLayouts = layouts.ptr(); + if (push_constant.push_constant_size) { + VkPushConstantRange push_constant_range; + push_constant_range.stageFlags = push_constant.push_constants_vk_stage; + push_constant_range.offset = 0; + push_constant_range.size = push_constant.push_constant_size; + + pipeline_layout_create_info.pushConstantRangeCount = 1; + pipeline_layout_create_info.pPushConstantRanges = &push_constant_range; + } else { + pipeline_layout_create_info.pushConstantRangeCount = 0; + pipeline_layout_create_info.pPushConstantRanges = NULL; + } + + VkResult err = vkCreatePipelineLayout(device, &pipeline_layout_create_info, NULL, &shader.pipeline_layout); + + if (err) { + error_text = "Error creating pipeline layout."; + success = false; + } + } + + if (!success) { + //clean up if failed + for (int i = 0; i < shader.pipeline_stages.size(); i++) { + vkDestroyShaderModule(device, shader.pipeline_stages[i].module, NULL); + } + + for (int i = 0; i < shader.sets.size(); i++) { + vkDestroyDescriptorSetLayout(device, shader.sets[i].descriptor_set_layout, NULL); + } + + ERR_FAIL_V_MSG(RID(), error_text); + } + + return shader_owner.make_rid(shader); +} + +uint32_t RenderingDeviceVulkan::shader_get_vertex_input_attribute_mask(RID p_shader) { + _THREAD_SAFE_METHOD_ + + const Shader *shader = shader_owner.getornull(p_shader); + ERR_FAIL_COND_V(!shader, 0); + return shader->vertex_input_mask; +} + +/******************/ +/**** UNIFORMS ****/ +/******************/ + +RID RenderingDeviceVulkan::uniform_buffer_create(uint32_t p_size_bytes, const PoolVector<uint8_t> &p_data) { + + _THREAD_SAFE_METHOD_ + + ERR_FAIL_COND_V(p_data.size() && (uint32_t)p_data.size() != p_size_bytes, RID()); + + Buffer buffer; + Error err = _buffer_allocate(&buffer, p_size_bytes, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VMA_MEMORY_USAGE_GPU_ONLY); + ERR_FAIL_COND_V(err != OK, RID()); + if (p_data.size()) { + uint64_t data_size = p_data.size(); + PoolVector<uint8_t>::Read r = p_data.read(); + _buffer_update(&buffer, 0, r.ptr(), data_size); + _buffer_memory_barrier(buffer.buffer, 0, data_size, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_UNIFORM_READ_BIT, false); + } + return uniform_buffer_owner.make_rid(buffer); +} + +RID RenderingDeviceVulkan::storage_buffer_create(uint32_t p_size_bytes, const PoolVector<uint8_t> &p_data) { + + _THREAD_SAFE_METHOD_ + + ERR_FAIL_COND_V(p_data.size() && (uint32_t)p_data.size() != p_size_bytes, RID()); + + Buffer buffer; + Error err = _buffer_allocate(&buffer, p_size_bytes, VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, VMA_MEMORY_USAGE_GPU_ONLY); + ERR_FAIL_COND_V(err != OK, RID()); + + if (p_data.size()) { + uint64_t data_size = p_data.size(); + PoolVector<uint8_t>::Read r = p_data.read(); + _buffer_update(&buffer, 0, r.ptr(), data_size); + _buffer_memory_barrier(buffer.buffer, 0, data_size, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT, false); + } + return storage_buffer_owner.make_rid(buffer); +} + +RID RenderingDeviceVulkan::texture_buffer_create(uint32_t p_size_elements, DataFormat p_format, const PoolVector<uint8_t> &p_data) { + + _THREAD_SAFE_METHOD_ + + uint32_t element_size = get_format_vertex_size(p_format); + ERR_FAIL_COND_V_MSG(element_size == 0, RID(), "Format requested is not supported for texture buffers"); + uint64_t size_bytes = uint64_t(element_size) * p_size_elements; + + ERR_FAIL_COND_V(p_data.size() && (uint32_t)p_data.size() != size_bytes, RID()); + + TextureBuffer texture_buffer; + Error err = _buffer_allocate(&texture_buffer.buffer, size_bytes, VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT, VMA_MEMORY_USAGE_GPU_ONLY); + ERR_FAIL_COND_V(err != OK, RID()); + + if (p_data.size()) { + uint64_t data_size = p_data.size(); + PoolVector<uint8_t>::Read r = p_data.read(); + _buffer_update(&texture_buffer.buffer, 0, r.ptr(), data_size); + _buffer_memory_barrier(texture_buffer.buffer.buffer, 0, data_size, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, false); + } + + VkBufferViewCreateInfo view_create_info; + view_create_info.sType = VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO; + view_create_info.pNext = NULL; + view_create_info.flags = 0; + view_create_info.buffer = texture_buffer.buffer.buffer; + view_create_info.format = vulkan_formats[p_format]; + view_create_info.offset = 0; + view_create_info.range = size_bytes; + + texture_buffer.view = VK_NULL_HANDLE; + + VkResult res = vkCreateBufferView(device, &view_create_info, NULL, &texture_buffer.view); + if (res) { + _buffer_free(&texture_buffer.buffer); + ERR_FAIL_V_MSG(RID(), "Unable to create buffer view"); + } + + //allocate the view + return texture_buffer_owner.make_rid(texture_buffer); +} + +RenderingDeviceVulkan::DescriptorPool *RenderingDeviceVulkan::_descriptor_pool_allocate(const DescriptorPoolKey &p_key) { + if (!descriptor_pools.has(p_key)) { + descriptor_pools[p_key] = Set<DescriptorPool *>(); + } + + DescriptorPool *pool = NULL; + + for (Set<DescriptorPool *>::Element *E = descriptor_pools[p_key].front(); E; E = E->next()) { + if (E->get()->usage < max_descriptors_per_pool) { + pool = E->get(); + break; + } + } + + if (!pool) { + //create a new one + pool = memnew(DescriptorPool); + pool->usage = 0; + + VkDescriptorPoolCreateInfo descriptor_pool_create_info; + descriptor_pool_create_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; + descriptor_pool_create_info.pNext = NULL; + descriptor_pool_create_info.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT; // can't think how somebody may NOT need this flag.. + descriptor_pool_create_info.maxSets = max_descriptors_per_pool; + Vector<VkDescriptorPoolSize> sizes; + //here comes more vulkan API strangeness + + if (p_key.uniform_type[UNIFORM_TYPE_SAMPLER]) { + VkDescriptorPoolSize s; + s.type = VK_DESCRIPTOR_TYPE_SAMPLER; + s.descriptorCount = p_key.uniform_type[UNIFORM_TYPE_SAMPLER] * max_descriptors_per_pool; + sizes.push_back(s); + } + if (p_key.uniform_type[UNIFORM_TYPE_SAMPLER_WITH_TEXTURE]) { + VkDescriptorPoolSize s; + s.type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + s.descriptorCount = p_key.uniform_type[UNIFORM_TYPE_SAMPLER_WITH_TEXTURE] * max_descriptors_per_pool; + sizes.push_back(s); + } + if (p_key.uniform_type[UNIFORM_TYPE_TEXTURE]) { + VkDescriptorPoolSize s; + s.type = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; + s.descriptorCount = p_key.uniform_type[UNIFORM_TYPE_TEXTURE] * max_descriptors_per_pool; + sizes.push_back(s); + } + if (p_key.uniform_type[UNIFORM_TYPE_IMAGE]) { + VkDescriptorPoolSize s; + s.type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; + s.descriptorCount = p_key.uniform_type[UNIFORM_TYPE_IMAGE] * max_descriptors_per_pool; + sizes.push_back(s); + } + if (p_key.uniform_type[UNIFORM_TYPE_TEXTURE_BUFFER] || p_key.uniform_type[UNIFORM_TYPE_SAMPLER_WITH_TEXTURE_BUFFER]) { + VkDescriptorPoolSize s; + s.type = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER; + s.descriptorCount = (p_key.uniform_type[UNIFORM_TYPE_TEXTURE_BUFFER] + p_key.uniform_type[UNIFORM_TYPE_SAMPLER_WITH_TEXTURE_BUFFER]) * max_descriptors_per_pool; + sizes.push_back(s); + } + if (p_key.uniform_type[UNIFORM_TYPE_IMAGE_BUFFER]) { + VkDescriptorPoolSize s; + s.type = VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER; + s.descriptorCount = p_key.uniform_type[UNIFORM_TYPE_IMAGE_BUFFER] * max_descriptors_per_pool; + sizes.push_back(s); + } + if (p_key.uniform_type[UNIFORM_TYPE_UNIFORM_BUFFER]) { + VkDescriptorPoolSize s; + s.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + s.descriptorCount = p_key.uniform_type[UNIFORM_TYPE_UNIFORM_BUFFER] * max_descriptors_per_pool; + sizes.push_back(s); + } + + if (p_key.uniform_type[UNIFORM_TYPE_STORAGE_BUFFER]) { + VkDescriptorPoolSize s; + s.type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; + s.descriptorCount = p_key.uniform_type[UNIFORM_TYPE_STORAGE_BUFFER] * max_descriptors_per_pool; + sizes.push_back(s); + } + + if (p_key.uniform_type[UNIFORM_TYPE_INPUT_ATTACHMENT]) { + VkDescriptorPoolSize s; + s.type = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT; + s.descriptorCount = p_key.uniform_type[UNIFORM_TYPE_INPUT_ATTACHMENT] * max_descriptors_per_pool; + sizes.push_back(s); + } + + descriptor_pool_create_info.poolSizeCount = sizes.size(); + descriptor_pool_create_info.pPoolSizes = sizes.ptr(); + VkResult res = vkCreateDescriptorPool(device, &descriptor_pool_create_info, NULL, &pool->pool); + ERR_FAIL_COND_V(res, NULL); + descriptor_pools[p_key].insert(pool); + } + + pool->usage++; + + return pool; +} + +void RenderingDeviceVulkan::_descriptor_pool_free(const DescriptorPoolKey &p_key, DescriptorPool *p_pool) { +#ifdef DEBUG_ENABLED + ERR_FAIL_COND(!descriptor_pools[p_key].has(p_pool)); +#endif + ERR_FAIL_COND(p_pool->usage == 0); + p_pool->usage--; + if (p_pool->usage == 0) { + vkDestroyDescriptorPool(device, p_pool->pool, NULL); + descriptor_pools[p_key].erase(p_pool); + memdelete(p_pool); + if (descriptor_pools[p_key].empty()) { + descriptor_pools.erase(p_key); + } + } +} + +RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms, RID p_shader, uint32_t p_shader_set) { + + _THREAD_SAFE_METHOD_ + + ERR_FAIL_COND_V(p_uniforms.size() == 0, RID()); + + Shader *shader = shader_owner.getornull(p_shader); + ERR_FAIL_COND_V(!shader, RID()); + + ERR_FAIL_COND_V_MSG(p_shader_set >= (uint32_t)shader->sets.size() || shader->sets[p_shader_set].uniform_info.size() == 0, RID(), + "Desired set (" + itos(p_shader_set) + ") not used by shader."); + //see that all sets in shader are satisfied + + const Shader::Set &set = shader->sets[p_shader_set]; + + uint32_t uniform_count = p_uniforms.size(); + const Uniform *uniforms = p_uniforms.ptr(); + + uint32_t set_uniform_count = set.uniform_info.size(); + const UniformInfo *set_uniforms = set.uniform_info.ptr(); + + Vector<VkWriteDescriptorSet> writes; + DescriptorPoolKey pool_key; + + //to keep them alive until update call + List<Vector<VkDescriptorBufferInfo> > buffer_infos; + List<Vector<VkBufferView> > buffer_views; + List<Vector<VkDescriptorImageInfo> > image_infos; + //used for verification to make sure a uniform set does not use a framebuffer bound texture + Vector<RID> attachable_textures; + Vector<Texture *> mutable_sampled_textures; + Vector<Texture *> mutable_storage_textures; + + for (uint32_t i = 0; i < set_uniform_count; i++) { + const UniformInfo &set_uniform = set_uniforms[i]; + int uniform_idx = -1; + for (int j = 0; j < (int)uniform_count; j++) { + if (uniforms[j].binding == set_uniform.binding) { + uniform_idx = j; + } + } + ERR_FAIL_COND_V_MSG(uniform_idx == -1, RID(), + "All the shader bindings for the given set must be covered by the uniforms provided."); + + const Uniform &uniform = uniforms[uniform_idx]; + + ERR_FAIL_COND_V_MSG(uniform.type != set_uniform.type, RID(), + "Mismatch uniform type for binding (" + itos(set_uniform.binding) + "). Expected '" + shader_uniform_names[set_uniform.type] + "', supplied: '" + shader_uniform_names[uniform.type] + "'."); + + VkWriteDescriptorSet write; //common header + write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + write.pNext = NULL; + write.dstSet = NULL; //will assign afterwards when everything is valid + write.dstBinding = set_uniform.binding; + uint32_t type_size = 1; + + switch (uniform.type) { + case UNIFORM_TYPE_SAMPLER: { + if (uniform.ids.size() != set_uniform.length) { + if (set_uniform.length > 1) { + ERR_FAIL_V_MSG(RID(), "Sampler (binding: " + itos(uniform.binding) + ") is an array of (" + itos(set_uniform.length) + ") sampler elements, so it should be provided equal number of sampler IDs to satisfy it (IDs provided: " + itos(uniform.ids.size()) + ")."); + } else { + ERR_FAIL_V_MSG(RID(), "Sampler (binding: " + itos(uniform.binding) + ") should provide one ID referencing a sampler (IDs provided: " + itos(uniform.ids.size()) + ")."); + } + } + + Vector<VkDescriptorImageInfo> image_info; + + for (int j = 0; j < uniform.ids.size(); j++) { + VkSampler *sampler = sampler_owner.getornull(uniform.ids[j]); + ERR_FAIL_COND_V_MSG(!sampler, RID(), "Sampler (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") is not a valid sampler."); + + VkDescriptorImageInfo img_info; + img_info.sampler = *sampler; + img_info.imageView = VK_NULL_HANDLE; + img_info.imageLayout = VK_IMAGE_LAYOUT_UNDEFINED; + + image_info.push_back(img_info); + } + + write.dstArrayElement = 0; + write.descriptorCount = uniform.ids.size(); + write.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER; + write.pImageInfo = image_infos.push_back(image_info)->get().ptr(); + write.pBufferInfo = NULL; + write.pTexelBufferView = NULL; + + type_size = uniform.ids.size(); + + } break; + case UNIFORM_TYPE_SAMPLER_WITH_TEXTURE: { + + if (uniform.ids.size() != set_uniform.length * 2) { + if (set_uniform.length > 1) { + ERR_FAIL_V_MSG(RID(), "SamplerTexture (binding: " + itos(uniform.binding) + ") is an array of (" + itos(set_uniform.length) + ") sampler&texture elements, so it should provided twice the amount of IDs (sampler,texture pairs) to satisfy it (IDs provided: " + itos(uniform.ids.size()) + ")."); + } else { + ERR_FAIL_V_MSG(RID(), "SamplerTexture (binding: " + itos(uniform.binding) + ") should provide two IDs referencing a sampler and then a texture (IDs provided: " + itos(uniform.ids.size()) + ")."); + } + } + + Vector<VkDescriptorImageInfo> image_info; + + for (int j = 0; j < uniform.ids.size(); j += 2) { + VkSampler *sampler = sampler_owner.getornull(uniform.ids[j + 0]); + ERR_FAIL_COND_V_MSG(!sampler, RID(), "SamplerBuffer (binding: " + itos(uniform.binding) + ", index " + itos(j + 1) + ") is not a valid sampler."); + + Texture *texture = texture_owner.getornull(uniform.ids[j + 1]); + ERR_FAIL_COND_V_MSG(!texture, RID(), "Texture (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") is not a valid texture."); + + ERR_FAIL_COND_V_MSG(!(texture->usage_flags & TEXTURE_USAGE_SAMPLING_BIT), RID(), + "Texture (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") needs the TEXTURE_USAGE_SAMPLING_BIT usage flag set in order to be used as uniform."); + + VkDescriptorImageInfo img_info; + img_info.sampler = *sampler; + img_info.imageView = texture->view; + + if (texture->usage_flags & (TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | TEXTURE_USAGE_RESOLVE_ATTACHMENT_BIT)) { + attachable_textures.push_back(texture->owner.is_valid() ? texture->owner : uniform.ids[j + 1]); + } + + if (texture->owner.is_valid()) { + texture = texture_owner.getornull(texture->owner); + ERR_FAIL_COND_V(!texture, RID()); //bug, should never happen + } + + img_info.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + + image_info.push_back(img_info); + + if (texture->usage_flags & TEXTURE_USAGE_STORAGE_BIT) { + //can also be used as storage, add to mutable sampled + mutable_sampled_textures.push_back(texture); + } + } + + write.dstArrayElement = 0; + write.descriptorCount = uniform.ids.size() / 2; + write.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + write.pImageInfo = image_infos.push_back(image_info)->get().ptr(); + write.pBufferInfo = NULL; + write.pTexelBufferView = NULL; + + type_size = uniform.ids.size() / 2; + + } break; + case UNIFORM_TYPE_TEXTURE: { + + if (uniform.ids.size() != set_uniform.length) { + if (set_uniform.length > 1) { + ERR_FAIL_V_MSG(RID(), "Texture (binding: " + itos(uniform.binding) + ") is an array of (" + itos(set_uniform.length) + ") textures, so it should be provided equal number of texture IDs to satisfy it (IDs provided: " + itos(uniform.ids.size()) + ")."); + } else { + ERR_FAIL_V_MSG(RID(), "Texture (binding: " + itos(uniform.binding) + ") should provide one ID referencing a texture (IDs provided: " + itos(uniform.ids.size()) + ")."); + } + } + + Vector<VkDescriptorImageInfo> image_info; + + for (int j = 0; j < uniform.ids.size(); j++) { + Texture *texture = texture_owner.getornull(uniform.ids[j]); + ERR_FAIL_COND_V_MSG(!texture, RID(), "Texture (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") is not a valid texture."); + + ERR_FAIL_COND_V_MSG(!(texture->usage_flags & TEXTURE_USAGE_SAMPLING_BIT), RID(), + "Texture (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") needs the TEXTURE_USAGE_SAMPLING_BIT usage flag set in order to be used as uniform."); + + VkDescriptorImageInfo img_info; + img_info.sampler = NULL; + img_info.imageView = texture->view; + + if (texture->usage_flags & (TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | TEXTURE_USAGE_RESOLVE_ATTACHMENT_BIT)) { + attachable_textures.push_back(texture->owner.is_valid() ? texture->owner : uniform.ids[j]); + } + + if (texture->owner.is_valid()) { + texture = texture_owner.getornull(texture->owner); + ERR_FAIL_COND_V(!texture, RID()); //bug, should never happen + } + + img_info.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + + image_info.push_back(img_info); + + if (texture->usage_flags & TEXTURE_USAGE_STORAGE_BIT) { + //can also be used as storage, add to mutable sampled + mutable_sampled_textures.push_back(texture); + } + } + + write.dstArrayElement = 0; + write.descriptorCount = uniform.ids.size(); + write.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; + write.pImageInfo = image_infos.push_back(image_info)->get().ptr(); + write.pBufferInfo = NULL; + write.pTexelBufferView = NULL; + + type_size = uniform.ids.size(); + } break; + case UNIFORM_TYPE_IMAGE: { + + if (uniform.ids.size() != set_uniform.length) { + if (set_uniform.length > 1) { + ERR_FAIL_V_MSG(RID(), "Image (binding: " + itos(uniform.binding) + ") is an array of (" + itos(set_uniform.length) + ") textures, so it should be provided equal number of texture IDs to satisfy it (IDs provided: " + itos(uniform.ids.size()) + ")."); + } else { + ERR_FAIL_V_MSG(RID(), "Image (binding: " + itos(uniform.binding) + ") should provide one ID referencing a texture (IDs provided: " + itos(uniform.ids.size()) + ")."); + } + } + + Vector<VkDescriptorImageInfo> image_info; + + for (int j = 0; j < uniform.ids.size(); j++) { + Texture *texture = texture_owner.getornull(uniform.ids[j]); + + ERR_FAIL_COND_V_MSG(!texture, RID(), + "Image (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") is not a valid texture."); + + ERR_FAIL_COND_V_MSG(!(texture->usage_flags & TEXTURE_USAGE_STORAGE_BIT), RID(), + "Image (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") needs the TEXTURE_USAGE_STORAGE_BIT usage flag set in order to be used as uniform."); + + VkDescriptorImageInfo img_info; + img_info.sampler = NULL; + img_info.imageView = texture->view; + + if (texture->owner.is_valid()) { + texture = texture_owner.getornull(texture->owner); + ERR_FAIL_COND_V(!texture, RID()); //bug, should never happen + } + + img_info.imageLayout = VK_IMAGE_LAYOUT_GENERAL; + + image_info.push_back(img_info); + + if (texture->usage_flags & TEXTURE_USAGE_SAMPLING_BIT) { + //can also be used as storage, add to mutable sampled + mutable_storage_textures.push_back(texture); + } + } + + write.dstArrayElement = 0; + write.descriptorCount = uniform.ids.size(); + write.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; + write.pImageInfo = image_infos.push_back(image_info)->get().ptr(); + write.pBufferInfo = NULL; + write.pTexelBufferView = NULL; + + type_size = uniform.ids.size(); + + } break; + case UNIFORM_TYPE_TEXTURE_BUFFER: { + if (uniform.ids.size() != set_uniform.length) { + if (set_uniform.length > 1) { + ERR_FAIL_V_MSG(RID(), "Buffer (binding: " + itos(uniform.binding) + ") is an array of (" + itos(set_uniform.length) + ") texture buffer elements, so it should be provided equal number of texture buffer IDs to satisfy it (IDs provided: " + itos(uniform.ids.size()) + ")."); + } else { + ERR_FAIL_V_MSG(RID(), "Buffer (binding: " + itos(uniform.binding) + ") should provide one ID referencing a texture buffer (IDs provided: " + itos(uniform.ids.size()) + ")."); + } + } + + Vector<VkDescriptorBufferInfo> buffer_info; + Vector<VkBufferView> buffer_view; + + for (int j = 0; j < uniform.ids.size(); j++) { + TextureBuffer *buffer = texture_buffer_owner.getornull(uniform.ids[j]); + ERR_FAIL_COND_V_MSG(!buffer, RID(), "Texture Buffer (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") is not a valid texture buffer."); + + buffer_info.push_back(buffer->buffer.buffer_info); + buffer_view.push_back(buffer->view); + } + + write.dstArrayElement = 0; + write.descriptorCount = uniform.ids.size(); + write.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER; + write.pImageInfo = NULL; + write.pBufferInfo = buffer_infos.push_back(buffer_info)->get().ptr(); + write.pTexelBufferView = buffer_views.push_back(buffer_view)->get().ptr(); + + type_size = uniform.ids.size(); + + } break; + case UNIFORM_TYPE_SAMPLER_WITH_TEXTURE_BUFFER: { + + if (uniform.ids.size() != set_uniform.length * 2) { + if (set_uniform.length > 1) { + ERR_FAIL_V_MSG(RID(), "SamplerBuffer (binding: " + itos(uniform.binding) + ") is an array of (" + itos(set_uniform.length) + ") sampler buffer elements, so it should provided twice the amount of IDs (sampler,buffer pairs) to satisfy it (IDs provided: " + itos(uniform.ids.size()) + ")."); + } else { + ERR_FAIL_V_MSG(RID(), "SamplerBuffer (binding: " + itos(uniform.binding) + ") should provide two IDs referencing a sampler and then a texture buffer (IDs provided: " + itos(uniform.ids.size()) + ")."); + } + } + + Vector<VkDescriptorImageInfo> image_info; + Vector<VkDescriptorBufferInfo> buffer_info; + Vector<VkBufferView> buffer_view; + + for (int j = 0; j < uniform.ids.size(); j += 2) { + VkSampler *sampler = sampler_owner.getornull(uniform.ids[j + 0]); + ERR_FAIL_COND_V_MSG(!sampler, RID(), "SamplerBuffer (binding: " + itos(uniform.binding) + ", index " + itos(j + 1) + ") is not a valid sampler."); + + TextureBuffer *buffer = texture_buffer_owner.getornull(uniform.ids[j + 1]); + + VkDescriptorImageInfo img_info; + img_info.sampler = *sampler; + img_info.imageView = VK_NULL_HANDLE; + img_info.imageLayout = VK_IMAGE_LAYOUT_UNDEFINED; + + image_info.push_back(img_info); + + ERR_FAIL_COND_V_MSG(!buffer, RID(), "SamplerBuffer (binding: " + itos(uniform.binding) + ", index " + itos(j + 1) + ") is not a valid texture buffer."); + + buffer_info.push_back(buffer->buffer.buffer_info); + buffer_view.push_back(buffer->view); + } + + write.dstArrayElement = 0; + write.descriptorCount = uniform.ids.size() / 2; + write.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER; + write.pImageInfo = image_infos.push_back(image_info)->get().ptr(); + write.pBufferInfo = buffer_infos.push_back(buffer_info)->get().ptr(); + write.pTexelBufferView = buffer_views.push_back(buffer_view)->get().ptr(); + + type_size = uniform.ids.size() / 2; + } break; + case UNIFORM_TYPE_IMAGE_BUFFER: { + //todo + + } break; + case UNIFORM_TYPE_UNIFORM_BUFFER: { + ERR_FAIL_COND_V_MSG(uniform.ids.size() != 1, RID(), + "Uniform buffer supplied (binding: " + itos(uniform.binding) + ") must provide one ID (" + itos(uniform.ids.size()) + " provided)."); + + Buffer *buffer = uniform_buffer_owner.getornull(uniform.ids[0]); + ERR_FAIL_COND_V_MSG(!buffer, RID(), "Uniform buffer supplied (binding: " + itos(uniform.binding) + ") is invalid."); + + ERR_FAIL_COND_V_MSG(buffer->size != (uint32_t)set_uniform.length, RID(), + "Uniform buffer supplied (binding: " + itos(uniform.binding) + ") size (" + itos(buffer->size) + " does not match size of shader uniform: (" + itos(set_uniform.length) + ")."); + + write.dstArrayElement = 0; + write.descriptorCount = 1; + write.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + write.pImageInfo = NULL; + write.pBufferInfo = &buffer->buffer_info; + write.pTexelBufferView = NULL; + + } break; + case UNIFORM_TYPE_STORAGE_BUFFER: { + ERR_FAIL_COND_V_MSG(uniform.ids.size() != 1, RID(), + "Storage buffer supplied (binding: " + itos(uniform.binding) + ") must provide one ID (" + itos(uniform.ids.size()) + " provided)."); + + Buffer *buffer = storage_buffer_owner.getornull(uniform.ids[0]); + ERR_FAIL_COND_V_MSG(!buffer, RID(), "Storage buffer supplied (binding: " + itos(uniform.binding) + ") is invalid."); + + //if 0, then its sized on link time + ERR_FAIL_COND_V_MSG(set_uniform.length > 0 && buffer->size != (uint32_t)set_uniform.length, RID(), + "Storage buffer supplied (binding: " + itos(uniform.binding) + ") size (" + itos(buffer->size) + " does not match size of shader uniform: (" + itos(set_uniform.length) + ")."); + + write.dstArrayElement = 0; + write.descriptorCount = 1; + write.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; + write.pImageInfo = NULL; + write.pBufferInfo = &buffer->buffer_info; + write.pTexelBufferView = NULL; + } break; + case UNIFORM_TYPE_INPUT_ATTACHMENT: { + + } break; + default: { + } + } + + writes.push_back(write); + + ERR_FAIL_COND_V_MSG(pool_key.uniform_type[set_uniform.type] == MAX_DESCRIPTOR_POOL_ELEMENT, RID(), + "Uniform set reached the limit of bindings for the same type (" + itos(MAX_DESCRIPTOR_POOL_ELEMENT) + ")."); + pool_key.uniform_type[set_uniform.type] += type_size; + } + + //need a descriptor pool + DescriptorPool *pool = _descriptor_pool_allocate(pool_key); + + ERR_FAIL_COND_V(!pool, RID()); + + VkDescriptorSetAllocateInfo descriptor_set_allocate_info; + + descriptor_set_allocate_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; + descriptor_set_allocate_info.pNext = NULL; + descriptor_set_allocate_info.descriptorPool = pool->pool; + descriptor_set_allocate_info.descriptorSetCount = 1; + descriptor_set_allocate_info.pSetLayouts = &shader->sets[p_shader_set].descriptor_set_layout; + + VkDescriptorSet descriptor_set; + + VkResult res = vkAllocateDescriptorSets(device, &descriptor_set_allocate_info, &descriptor_set); + if (res) { + _descriptor_pool_free(pool_key, pool); // meh + ERR_FAIL_V_MSG(RID(), "Cannot allocate descriptor sets."); + } + + UniformSet uniform_set; + uniform_set.pool = pool; + uniform_set.pool_key = pool_key; + uniform_set.descriptor_set = descriptor_set; + uniform_set.format = shader->set_formats[p_shader_set]; + uniform_set.attachable_textures = attachable_textures; + uniform_set.mutable_sampled_textures = mutable_sampled_textures; + uniform_set.mutable_storage_textures = mutable_storage_textures; + uniform_set.shader_set = p_shader_set; + uniform_set.shader_id = p_shader; + + RID id = uniform_set_owner.make_rid(uniform_set); + //add dependencies + _add_dependency(id, p_shader); + for (uint32_t i = 0; i < uniform_count; i++) { + const Uniform &uniform = uniforms[i]; + int id_count = uniform.ids.size(); + const RID *ids = uniform.ids.ptr(); + for (int j = 0; j < id_count; j++) { + _add_dependency(id, ids[j]); + } + } + + //write the contents + if (writes.size()) { + for (int i = 0; i < writes.size(); i++) { + writes.write[i].dstSet = descriptor_set; + } + vkUpdateDescriptorSets(device, writes.size(), writes.ptr(), 0, NULL); + } + + return id; +} + +bool RenderingDeviceVulkan::uniform_set_is_valid(RID p_uniform_set) { + return uniform_set_owner.owns(p_uniform_set); +} + +Error RenderingDeviceVulkan::buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p_size, const void *p_data, bool p_sync_with_draw) { + _THREAD_SAFE_METHOD_ + + ERR_FAIL_COND_V_MSG(draw_list && p_sync_with_draw, ERR_INVALID_PARAMETER, + "Updating buffers in 'sync to draw' mode is forbidden during creation of a draw list"); + + VkPipelineStageFlags dst_stage_mask; + VkAccessFlags dst_access; + + Buffer *buffer = NULL; + if (vertex_buffer_owner.owns(p_buffer)) { + dst_stage_mask = VK_PIPELINE_STAGE_VERTEX_INPUT_BIT; + dst_access = VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT; + buffer = vertex_buffer_owner.getornull(p_buffer); + } else if (index_buffer_owner.owns(p_buffer)) { + dst_stage_mask = VK_PIPELINE_STAGE_VERTEX_INPUT_BIT; + dst_access = VK_ACCESS_INDEX_READ_BIT; + buffer = index_buffer_owner.getornull(p_buffer); + } else if (uniform_buffer_owner.owns(p_buffer)) { + dst_stage_mask = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; + dst_access = VK_ACCESS_UNIFORM_READ_BIT; + buffer = uniform_buffer_owner.getornull(p_buffer); + } else if (texture_buffer_owner.owns(p_buffer)) { + dst_stage_mask = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; + dst_access = VK_ACCESS_SHADER_READ_BIT; + buffer = &texture_buffer_owner.getornull(p_buffer)->buffer; + } else if (storage_buffer_owner.owns(p_buffer)) { + dst_stage_mask = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; + dst_access = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; + buffer = storage_buffer_owner.getornull(p_buffer); + } else { + ERR_FAIL_V_MSG(ERR_INVALID_PARAMETER, "Buffer argument is not a valid buffer of any type."); + } + + ERR_FAIL_COND_V_MSG(p_offset + p_size > buffer->size, ERR_INVALID_PARAMETER, + "Attempted to write buffer (" + itos((p_offset + p_size) - buffer->size) + " bytes) past the end."); + + Error err = _buffer_update(buffer, p_offset, (uint8_t *)p_data, p_size, p_sync_with_draw); + if (err) { + return err; + } + + _buffer_memory_barrier(buffer->buffer, p_offset, p_size, VK_PIPELINE_STAGE_TRANSFER_BIT, dst_stage_mask, VK_ACCESS_TRANSFER_WRITE_BIT, dst_access, p_sync_with_draw); +#ifdef FORCE_FULL_BARRIER + _full_barrier(p_sync_with_draw); +#else + _buffer_memory_barrier(buffer->buffer, p_offset, p_size, VK_PIPELINE_STAGE_TRANSFER_BIT, dst_stage_mask, VK_ACCESS_TRANSFER_WRITE_BIT, dst_access, p_sync_with_draw); +#endif + return err; +} + +PoolVector<uint8_t> RenderingDeviceVulkan::buffer_get_data(RID p_buffer) { + + _THREAD_SAFE_METHOD_ + + Buffer *buffer = NULL; + if (vertex_buffer_owner.owns(p_buffer)) { + buffer = vertex_buffer_owner.getornull(p_buffer); + } else if (index_buffer_owner.owns(p_buffer)) { + buffer = index_buffer_owner.getornull(p_buffer); + } else if (texture_buffer_owner.owns(p_buffer)) { + buffer = &texture_buffer_owner.getornull(p_buffer)->buffer; + } else if (storage_buffer_owner.owns(p_buffer)) { + buffer = storage_buffer_owner.getornull(p_buffer); + } else { + ERR_FAIL_V_MSG(PoolVector<uint8_t>(), "Buffer is either invalid or this type of buffer can't be retrieved. Only Index and Vertex buffers allow retrieving."); + } + + VkCommandBuffer command_buffer = frames[frame].setup_command_buffer; + Buffer tmp_buffer; + _buffer_allocate(&tmp_buffer, buffer->size, VK_BUFFER_USAGE_TRANSFER_DST_BIT, VMA_MEMORY_USAGE_CPU_ONLY); + VkBufferCopy region; + region.srcOffset = 0; + region.dstOffset = 0; + region.size = buffer->size; + vkCmdCopyBuffer(command_buffer, buffer->buffer, tmp_buffer.buffer, 1, ®ion); //dst buffer is in CPU, but I wonder if src buffer needs a barrier for this.. + //flush everything so memory can be safely mapped + _flush(true); + + void *buffer_mem; + VkResult vkerr = vmaMapMemory(allocator, tmp_buffer.allocation, &buffer_mem); + if (vkerr) { + ERR_FAIL_V(PoolVector<uint8_t>()); + } + + PoolVector<uint8_t> buffer_data; + { + + buffer_data.resize(buffer->size); + PoolVector<uint8_t>::Write w = buffer_data.write(); + copymem(w.ptr(), buffer_mem, buffer->size); + } + + vmaUnmapMemory(allocator, tmp_buffer.allocation); + + _buffer_free(&tmp_buffer); + + return buffer_data; +} + +/*************************/ +/**** RENDER PIPELINE ****/ +/*************************/ + +RID RenderingDeviceVulkan::render_pipeline_create(RID p_shader, FramebufferFormatID p_framebuffer_format, VertexFormatID p_vertex_format, RenderPrimitive p_render_primitive, const PipelineRasterizationState &p_rasterization_state, const PipelineMultisampleState &p_multisample_state, const PipelineDepthStencilState &p_depth_stencil_state, const PipelineColorBlendState &p_blend_state, int p_dynamic_state_flags) { + + _THREAD_SAFE_METHOD_ + + //needs a shader + Shader *shader = shader_owner.getornull(p_shader); + ERR_FAIL_COND_V(!shader, RID()); + + ERR_FAIL_COND_V_MSG(shader->is_compute, RID(), + "Compute shaders can't be used in render pipelines"); + + if (p_framebuffer_format == INVALID_ID) { + //if nothing provided, use an empty one (no attachments) + p_framebuffer_format = framebuffer_format_create(Vector<AttachmentFormat>()); + } + ERR_FAIL_COND_V(!framebuffer_formats.has(p_framebuffer_format), RID()); + const FramebufferFormat &fb_format = framebuffer_formats[p_framebuffer_format]; + + { //validate shader vs framebuffer + + ERR_FAIL_COND_V_MSG(shader->fragment_outputs != fb_format.color_attachments, RID(), + "Mismatch fragment output bindings (" + itos(shader->fragment_outputs) + ") and framebuffer color buffers (" + itos(fb_format.color_attachments) + ") when binding both in render pipeline."); + } + //vertex + VkPipelineVertexInputStateCreateInfo pipeline_vertex_input_state_create_info; + + if (p_vertex_format != INVALID_ID) { + //uses vertices, else it does not + ERR_FAIL_COND_V(!vertex_formats.has(p_vertex_format), RID()); + const VertexDescriptionCache &vd = vertex_formats[p_vertex_format]; + + pipeline_vertex_input_state_create_info = vd.create_info; + + //validate with inputs + for (uint32_t i = 0; i < 32; i++) { + if (!(shader->vertex_input_mask & (1 << i))) { + continue; + } + bool found = false; + for (int j = 0; j < vd.vertex_formats.size(); j++) { + if (vd.vertex_formats[j].location == i) { + found = true; + } + } + + ERR_FAIL_COND_V_MSG(!found, RID(), + "Shader vertex input location (" + itos(i) + ") not provided in vertex input description for pipeline creation."); + } + + } else { + //does not use vertices + pipeline_vertex_input_state_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; + pipeline_vertex_input_state_create_info.pNext = NULL; + pipeline_vertex_input_state_create_info.flags = 0; + pipeline_vertex_input_state_create_info.vertexBindingDescriptionCount = 0; + pipeline_vertex_input_state_create_info.pVertexBindingDescriptions = NULL; + pipeline_vertex_input_state_create_info.vertexAttributeDescriptionCount = 0; + pipeline_vertex_input_state_create_info.pVertexAttributeDescriptions = NULL; + + ERR_FAIL_COND_V_MSG(shader->vertex_input_mask != 0, RID(), + "Shader contains vertex inputs, but no vertex input description was provided for pipeline creation."); + } + //input assembly + + ERR_FAIL_INDEX_V(p_render_primitive, RENDER_PRIMITIVE_MAX, RID()); + + VkPipelineInputAssemblyStateCreateInfo input_assembly_create_info; + input_assembly_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; + input_assembly_create_info.pNext = NULL; + input_assembly_create_info.flags = 0; + + static const VkPrimitiveTopology topology_list[RENDER_PRIMITIVE_MAX] = { + VK_PRIMITIVE_TOPOLOGY_POINT_LIST, + VK_PRIMITIVE_TOPOLOGY_LINE_LIST, + VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY, + VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, + VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY, + VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, + VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY, + VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, + VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY, + VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, + VK_PRIMITIVE_TOPOLOGY_PATCH_LIST + }; + + input_assembly_create_info.topology = topology_list[p_render_primitive]; + input_assembly_create_info.primitiveRestartEnable = (p_render_primitive == RENDER_PRIMITIVE_TRIANGLE_STRIPS_WITH_RESTART_INDEX); + + //tesselation + VkPipelineTessellationStateCreateInfo tesselation_create_info; + tesselation_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO; + tesselation_create_info.pNext = NULL; + tesselation_create_info.flags = 0; + ERR_FAIL_COND_V(p_rasterization_state.patch_control_points < 1 || p_rasterization_state.patch_control_points > limits.maxTessellationPatchSize, RID()); + tesselation_create_info.patchControlPoints = p_rasterization_state.patch_control_points; + + VkPipelineViewportStateCreateInfo viewport_state_create_info; + viewport_state_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; + viewport_state_create_info.pNext = NULL; + viewport_state_create_info.flags = 0; + viewport_state_create_info.viewportCount = 1; //if VR extensions are supported at some point, this will have to be customizable in the framebuffer format + viewport_state_create_info.pViewports = NULL; + viewport_state_create_info.scissorCount = 1; + viewport_state_create_info.pScissors = NULL; + + //rasterization + VkPipelineRasterizationStateCreateInfo rasterization_state_create_info; + rasterization_state_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; + rasterization_state_create_info.pNext = NULL; + rasterization_state_create_info.flags = 0; + rasterization_state_create_info.depthClampEnable = p_rasterization_state.enable_depth_clamp; + rasterization_state_create_info.rasterizerDiscardEnable = p_rasterization_state.discard_primitives; + rasterization_state_create_info.polygonMode = (p_rasterization_state.wireframe ? VK_POLYGON_MODE_LINE : VK_POLYGON_MODE_FILL); + static VkCullModeFlags cull_mode[3] = { + VK_CULL_MODE_NONE, + VK_CULL_MODE_FRONT_BIT, + VK_CULL_MODE_BACK_BIT + }; + + ERR_FAIL_INDEX_V(p_rasterization_state.cull_mode, 3, RID()); + rasterization_state_create_info.cullMode = cull_mode[p_rasterization_state.cull_mode]; + rasterization_state_create_info.frontFace = (p_rasterization_state.front_face == POLYGON_FRONT_FACE_CLOCKWISE ? VK_FRONT_FACE_CLOCKWISE : VK_FRONT_FACE_COUNTER_CLOCKWISE); + rasterization_state_create_info.depthBiasEnable = p_rasterization_state.depth_bias_enable; + rasterization_state_create_info.depthBiasConstantFactor = p_rasterization_state.depth_bias_constant_factor; + rasterization_state_create_info.depthBiasClamp = p_rasterization_state.depth_bias_clamp; + rasterization_state_create_info.depthBiasSlopeFactor = p_rasterization_state.depth_bias_slope_factor; + rasterization_state_create_info.lineWidth = p_rasterization_state.line_width; + + //multisample + VkPipelineMultisampleStateCreateInfo multisample_state_create_info; + multisample_state_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; + multisample_state_create_info.pNext = NULL; + multisample_state_create_info.flags = 0; + + multisample_state_create_info.rasterizationSamples = rasterization_sample_count[p_multisample_state.sample_count]; + multisample_state_create_info.sampleShadingEnable = p_multisample_state.enable_sample_shading; + multisample_state_create_info.minSampleShading = p_multisample_state.min_sample_shading; + Vector<VkSampleMask> sample_mask; + if (p_multisample_state.sample_mask.size()) { + //use sample mask + int rasterization_sample_mask_expected_size[TEXTURE_SAMPLES_MAX] = { + 1, 2, 4, 8, 16, 32, 64 + }; + ERR_FAIL_COND_V(rasterization_sample_mask_expected_size[p_multisample_state.sample_count] != p_multisample_state.sample_mask.size(), RID()); + sample_mask.resize(p_multisample_state.sample_mask.size()); + for (int i = 0; i < p_multisample_state.sample_mask.size(); i++) { + VkSampleMask mask = p_multisample_state.sample_mask[i]; + sample_mask.push_back(mask); + } + multisample_state_create_info.pSampleMask = sample_mask.ptr(); + } else { + multisample_state_create_info.pSampleMask = NULL; + } + + multisample_state_create_info.alphaToCoverageEnable = p_multisample_state.enable_alpha_to_coverage; + multisample_state_create_info.alphaToOneEnable = p_multisample_state.enable_alpha_to_one; + + //depth stencil + + VkPipelineDepthStencilStateCreateInfo depth_stencil_state_create_info; + depth_stencil_state_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; + depth_stencil_state_create_info.pNext = NULL; + depth_stencil_state_create_info.flags = 0; + depth_stencil_state_create_info.depthTestEnable = p_depth_stencil_state.enable_depth_test; + depth_stencil_state_create_info.depthWriteEnable = p_depth_stencil_state.enable_depth_write; + ERR_FAIL_INDEX_V(p_depth_stencil_state.depth_compare_operator, COMPARE_OP_MAX, RID()); + depth_stencil_state_create_info.depthCompareOp = compare_operators[p_depth_stencil_state.depth_compare_operator]; + depth_stencil_state_create_info.depthBoundsTestEnable = p_depth_stencil_state.enable_depth_range; + depth_stencil_state_create_info.stencilTestEnable = p_depth_stencil_state.enable_stencil; + + ERR_FAIL_INDEX_V(p_depth_stencil_state.stencil_operation_front.fail, STENCIL_OP_MAX, RID()); + depth_stencil_state_create_info.front.failOp = stencil_operations[p_depth_stencil_state.stencil_operation_front.fail]; + ERR_FAIL_INDEX_V(p_depth_stencil_state.stencil_operation_front.pass, STENCIL_OP_MAX, RID()); + depth_stencil_state_create_info.front.passOp = stencil_operations[p_depth_stencil_state.stencil_operation_front.pass]; + ERR_FAIL_INDEX_V(p_depth_stencil_state.stencil_operation_front.depth_fail, STENCIL_OP_MAX, RID()); + depth_stencil_state_create_info.front.depthFailOp = stencil_operations[p_depth_stencil_state.stencil_operation_front.depth_fail]; + ERR_FAIL_INDEX_V(p_depth_stencil_state.stencil_operation_front.compare, COMPARE_OP_MAX, RID()); + depth_stencil_state_create_info.front.compareOp = compare_operators[p_depth_stencil_state.stencil_operation_front.compare]; + depth_stencil_state_create_info.front.compareMask = p_depth_stencil_state.stencil_operation_front.compare_mask; + depth_stencil_state_create_info.front.writeMask = p_depth_stencil_state.stencil_operation_front.write_mask; + depth_stencil_state_create_info.front.reference = p_depth_stencil_state.stencil_operation_front.reference; + + ERR_FAIL_INDEX_V(p_depth_stencil_state.stencil_operation_back.fail, STENCIL_OP_MAX, RID()); + depth_stencil_state_create_info.back.failOp = stencil_operations[p_depth_stencil_state.stencil_operation_back.fail]; + ERR_FAIL_INDEX_V(p_depth_stencil_state.stencil_operation_back.pass, STENCIL_OP_MAX, RID()); + depth_stencil_state_create_info.back.passOp = stencil_operations[p_depth_stencil_state.stencil_operation_back.pass]; + ERR_FAIL_INDEX_V(p_depth_stencil_state.stencil_operation_back.depth_fail, STENCIL_OP_MAX, RID()); + depth_stencil_state_create_info.back.depthFailOp = stencil_operations[p_depth_stencil_state.stencil_operation_back.depth_fail]; + ERR_FAIL_INDEX_V(p_depth_stencil_state.stencil_operation_back.compare, COMPARE_OP_MAX, RID()); + depth_stencil_state_create_info.back.compareOp = compare_operators[p_depth_stencil_state.stencil_operation_back.compare]; + depth_stencil_state_create_info.back.compareMask = p_depth_stencil_state.stencil_operation_back.compare_mask; + depth_stencil_state_create_info.back.writeMask = p_depth_stencil_state.stencil_operation_back.write_mask; + depth_stencil_state_create_info.back.reference = p_depth_stencil_state.stencil_operation_back.reference; + + depth_stencil_state_create_info.minDepthBounds = p_depth_stencil_state.depth_range_min; + depth_stencil_state_create_info.maxDepthBounds = p_depth_stencil_state.depth_range_max; + + //blend state + VkPipelineColorBlendStateCreateInfo color_blend_state_create_info; + color_blend_state_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; + color_blend_state_create_info.pNext = NULL; + color_blend_state_create_info.flags = 0; + color_blend_state_create_info.logicOpEnable = p_blend_state.enable_logic_op; + ERR_FAIL_INDEX_V(p_blend_state.logic_op, LOGIC_OP_MAX, RID()); + color_blend_state_create_info.logicOp = logic_operations[p_blend_state.logic_op]; + + ERR_FAIL_COND_V(fb_format.color_attachments != p_blend_state.attachments.size(), RID()); + + Vector<VkPipelineColorBlendAttachmentState> attachment_states; + + for (int i = 0; i < p_blend_state.attachments.size(); i++) { + VkPipelineColorBlendAttachmentState state; + state.blendEnable = p_blend_state.attachments[i].enable_blend; + + ERR_FAIL_INDEX_V(p_blend_state.attachments[i].src_color_blend_factor, BLEND_FACTOR_MAX, RID()); + state.srcColorBlendFactor = blend_factors[p_blend_state.attachments[i].src_color_blend_factor]; + ERR_FAIL_INDEX_V(p_blend_state.attachments[i].dst_color_blend_factor, BLEND_FACTOR_MAX, RID()); + state.dstColorBlendFactor = blend_factors[p_blend_state.attachments[i].dst_color_blend_factor]; + ERR_FAIL_INDEX_V(p_blend_state.attachments[i].color_blend_op, BLEND_OP_MAX, RID()); + state.colorBlendOp = blend_operations[p_blend_state.attachments[i].color_blend_op]; + + ERR_FAIL_INDEX_V(p_blend_state.attachments[i].src_alpha_blend_factor, BLEND_FACTOR_MAX, RID()); + state.srcAlphaBlendFactor = blend_factors[p_blend_state.attachments[i].src_alpha_blend_factor]; + ERR_FAIL_INDEX_V(p_blend_state.attachments[i].dst_alpha_blend_factor, BLEND_FACTOR_MAX, RID()); + state.dstAlphaBlendFactor = blend_factors[p_blend_state.attachments[i].dst_alpha_blend_factor]; + ERR_FAIL_INDEX_V(p_blend_state.attachments[i].alpha_blend_op, BLEND_OP_MAX, RID()); + state.alphaBlendOp = blend_operations[p_blend_state.attachments[i].alpha_blend_op]; + + state.colorWriteMask = 0; + if (p_blend_state.attachments[i].write_r) { + state.colorWriteMask |= VK_COLOR_COMPONENT_R_BIT; + } + if (p_blend_state.attachments[i].write_g) { + state.colorWriteMask |= VK_COLOR_COMPONENT_G_BIT; + } + if (p_blend_state.attachments[i].write_b) { + state.colorWriteMask |= VK_COLOR_COMPONENT_B_BIT; + } + if (p_blend_state.attachments[i].write_a) { + state.colorWriteMask |= VK_COLOR_COMPONENT_A_BIT; + } + + attachment_states.push_back(state); + }; + + color_blend_state_create_info.attachmentCount = attachment_states.size(); + color_blend_state_create_info.pAttachments = attachment_states.ptr(); + + color_blend_state_create_info.blendConstants[0] = p_blend_state.blend_constant.r; + color_blend_state_create_info.blendConstants[1] = p_blend_state.blend_constant.g; + color_blend_state_create_info.blendConstants[2] = p_blend_state.blend_constant.b; + color_blend_state_create_info.blendConstants[3] = p_blend_state.blend_constant.a; + + //dynamic state + + VkPipelineDynamicStateCreateInfo dynamic_state_create_info; + dynamic_state_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; + dynamic_state_create_info.pNext = NULL; + dynamic_state_create_info.flags = 0; + Vector<VkDynamicState> dynamic_states; //vulkan is weird.. + + dynamic_states.push_back(VK_DYNAMIC_STATE_VIEWPORT); //viewport and scissor are always dynamic + dynamic_states.push_back(VK_DYNAMIC_STATE_SCISSOR); + + if (p_dynamic_state_flags & DYNAMIC_STATE_LINE_WIDTH) { + dynamic_states.push_back(VK_DYNAMIC_STATE_LINE_WIDTH); + } + + if (p_dynamic_state_flags & DYNAMIC_STATE_DEPTH_BIAS) { + dynamic_states.push_back(VK_DYNAMIC_STATE_DEPTH_BIAS); + } + + if (p_dynamic_state_flags & DYNAMIC_STATE_BLEND_CONSTANTS) { + dynamic_states.push_back(VK_DYNAMIC_STATE_BLEND_CONSTANTS); + } + + if (p_dynamic_state_flags & DYNAMIC_STATE_DEPTH_BOUNDS) { + dynamic_states.push_back(VK_DYNAMIC_STATE_DEPTH_BOUNDS); + } + + if (p_dynamic_state_flags & DYNAMIC_STATE_STENCIL_COMPARE_MASK) { + dynamic_states.push_back(VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK); + } + + if (p_dynamic_state_flags & DYNAMIC_STATE_STENCIL_WRITE_MASK) { + dynamic_states.push_back(VK_DYNAMIC_STATE_STENCIL_WRITE_MASK); + } + + if (p_dynamic_state_flags & DYNAMIC_STATE_STENCIL_REFERENCE) { + dynamic_states.push_back(VK_DYNAMIC_STATE_STENCIL_REFERENCE); + } + + dynamic_state_create_info.dynamicStateCount = dynamic_states.size(); + dynamic_state_create_info.pDynamicStates = dynamic_states.ptr(); + + //finally, pipeline create info + VkGraphicsPipelineCreateInfo graphics_pipeline_create_info; + + graphics_pipeline_create_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; + graphics_pipeline_create_info.pNext = NULL; + graphics_pipeline_create_info.flags = 0; + + graphics_pipeline_create_info.stageCount = shader->pipeline_stages.size(); + graphics_pipeline_create_info.pStages = shader->pipeline_stages.ptr(); + graphics_pipeline_create_info.pVertexInputState = &pipeline_vertex_input_state_create_info; + graphics_pipeline_create_info.pInputAssemblyState = &input_assembly_create_info; + graphics_pipeline_create_info.pTessellationState = &tesselation_create_info; + graphics_pipeline_create_info.pViewportState = &viewport_state_create_info; + graphics_pipeline_create_info.pRasterizationState = &rasterization_state_create_info; + graphics_pipeline_create_info.pMultisampleState = &multisample_state_create_info; + graphics_pipeline_create_info.pDepthStencilState = &depth_stencil_state_create_info; + graphics_pipeline_create_info.pColorBlendState = &color_blend_state_create_info; + graphics_pipeline_create_info.pDynamicState = &dynamic_state_create_info; + graphics_pipeline_create_info.layout = shader->pipeline_layout; + graphics_pipeline_create_info.renderPass = fb_format.render_pass; + + graphics_pipeline_create_info.subpass = 0; + graphics_pipeline_create_info.basePipelineHandle = NULL; + graphics_pipeline_create_info.basePipelineIndex = 0; + + RenderPipeline pipeline; + VkResult err = vkCreateGraphicsPipelines(device, NULL, 1, &graphics_pipeline_create_info, NULL, &pipeline.pipeline); + ERR_FAIL_COND_V(err, RID()); + + pipeline.set_formats = shader->set_formats; + pipeline.push_constant_stages = shader->push_constant.push_constants_vk_stage; + pipeline.pipeline_layout = shader->pipeline_layout; + pipeline.shader = p_shader; + pipeline.push_constant_size = shader->push_constant.push_constant_size; + +#ifdef DEBUG_ENABLED + pipeline.validation.dynamic_state = p_dynamic_state_flags; + pipeline.validation.framebuffer_format = p_framebuffer_format; + pipeline.validation.vertex_format = p_vertex_format; + pipeline.validation.uses_restart_indices = input_assembly_create_info.primitiveRestartEnable; + + static const uint32_t primitive_divisor[RENDER_PRIMITIVE_MAX] = { + 1, 2, 1, 1, 1, 3, 1, 1, 1, 1, 1 + }; + pipeline.validation.primitive_divisor = primitive_divisor[p_render_primitive]; + static const uint32_t primitive_minimum[RENDER_PRIMITIVE_MAX] = { + 1, + 2, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 3, + 1, + }; + pipeline.validation.primitive_minimum = primitive_minimum[p_render_primitive]; +#endif + //create ID to associate with this pipeline + RID id = render_pipeline_owner.make_rid(pipeline); + //now add aall the dependencies + _add_dependency(id, p_shader); + return id; +} + +bool RenderingDeviceVulkan::render_pipeline_is_valid(RID p_pipeline) { + _THREAD_SAFE_METHOD_ + return render_pipeline_owner.owns(p_pipeline); +} + +/**************************/ +/**** COMPUTE PIPELINE ****/ +/**************************/ + +RID RenderingDeviceVulkan::compute_pipeline_create(RID p_shader) { + _THREAD_SAFE_METHOD_ + + //needs a shader + Shader *shader = shader_owner.getornull(p_shader); + ERR_FAIL_COND_V(!shader, RID()); + + ERR_FAIL_COND_V_MSG(!shader->is_compute, RID(), + "Non-compute shaders can't be used in compute pipelines"); + + //finally, pipeline create info + VkComputePipelineCreateInfo compute_pipeline_create_info; + + compute_pipeline_create_info.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO; + compute_pipeline_create_info.pNext = NULL; + compute_pipeline_create_info.flags = 0; + + compute_pipeline_create_info.stage = shader->pipeline_stages[0]; + compute_pipeline_create_info.layout = shader->pipeline_layout; + compute_pipeline_create_info.basePipelineHandle = NULL; + compute_pipeline_create_info.basePipelineIndex = 0; + + ComputePipeline pipeline; + VkResult err = vkCreateComputePipelines(device, NULL, 1, &compute_pipeline_create_info, NULL, &pipeline.pipeline); + ERR_FAIL_COND_V(err, RID()); + + pipeline.set_formats = shader->set_formats; + pipeline.push_constant_stages = shader->push_constant.push_constants_vk_stage; + pipeline.pipeline_layout = shader->pipeline_layout; + pipeline.shader = p_shader; + pipeline.push_constant_size = shader->push_constant.push_constant_size; + + //create ID to associate with this pipeline + RID id = compute_pipeline_owner.make_rid(pipeline); + //now add aall the dependencies + _add_dependency(id, p_shader); + return id; +} + +bool RenderingDeviceVulkan::compute_pipeline_is_valid(RID p_pipeline) { + + return compute_pipeline_owner.owns(p_pipeline); +} + +/****************/ +/**** SCREEN ****/ +/****************/ + +int RenderingDeviceVulkan::screen_get_width(int p_screen) const { + _THREAD_SAFE_METHOD_ + + return context->window_get_width(p_screen); +} +int RenderingDeviceVulkan::screen_get_height(int p_screen) const { + _THREAD_SAFE_METHOD_ + + return context->window_get_height(p_screen); +} +RenderingDevice::FramebufferFormatID RenderingDeviceVulkan::screen_get_framebuffer_format() const { + + _THREAD_SAFE_METHOD_ + + //very hacky, but not used often per frame so I guess ok + VkFormat vkformat = context->get_screen_format(); + DataFormat format = DATA_FORMAT_MAX; + for (int i = 0; i < DATA_FORMAT_MAX; i++) { + if (vkformat == vulkan_formats[i]) { + format = DataFormat(i); + break; + } + } + + ERR_FAIL_COND_V(format == DATA_FORMAT_MAX, INVALID_ID); + + AttachmentFormat attachment; + attachment.format = format; + attachment.samples = TEXTURE_SAMPLES_1; + attachment.usage_flags = TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; + Vector<AttachmentFormat> screen_attachment; + screen_attachment.push_back(attachment); + return const_cast<RenderingDeviceVulkan *>(this)->framebuffer_format_create(screen_attachment); +} + +/*******************/ +/**** DRAW LIST ****/ +/*******************/ + +RenderingDevice::DrawListID RenderingDeviceVulkan::draw_list_begin_for_screen(int p_screen, const Color &p_clear_color) { + + _THREAD_SAFE_METHOD_ + + ERR_FAIL_COND_V_MSG(draw_list != NULL, INVALID_ID, "Only one draw list can be active at the same time."); + ERR_FAIL_COND_V_MSG(compute_list != NULL, INVALID_ID, "Only one draw/compute list can be active at the same time."); + + VkCommandBuffer command_buffer = frames[frame].draw_command_buffer; + draw_list = memnew(DrawList); + draw_list->command_buffer = command_buffer; +#ifdef DEBUG_ENABLED + draw_list->validation.framebuffer_format = screen_get_framebuffer_format(); +#endif + draw_list_count = 0; + draw_list_split = false; + + VkRenderPassBeginInfo render_pass_begin; + render_pass_begin.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; + render_pass_begin.pNext = NULL; + render_pass_begin.renderPass = context->window_get_render_pass(p_screen); + render_pass_begin.framebuffer = context->window_get_framebuffer(p_screen); + + render_pass_begin.renderArea.extent.width = context->window_get_width(p_screen); + render_pass_begin.renderArea.extent.height = context->window_get_height(p_screen); + render_pass_begin.renderArea.offset.x = 0; + render_pass_begin.renderArea.offset.y = 0; + + render_pass_begin.clearValueCount = 1; + + VkClearValue clear_value; + clear_value.color.float32[0] = p_clear_color.r; + clear_value.color.float32[1] = p_clear_color.g; + clear_value.color.float32[2] = p_clear_color.b; + clear_value.color.float32[3] = p_clear_color.a; + + render_pass_begin.pClearValues = &clear_value; + + vkCmdBeginRenderPass(command_buffer, &render_pass_begin, VK_SUBPASS_CONTENTS_INLINE); + + uint32_t size_x = screen_get_width(p_screen); + uint32_t size_y = screen_get_height(p_screen); + + VkViewport viewport; + viewport.x = 0; + viewport.y = 0; + viewport.width = size_x; + viewport.height = size_y; + viewport.minDepth = 0; + viewport.maxDepth = 1.0; + + vkCmdSetViewport(command_buffer, 0, 1, &viewport); + + VkRect2D scissor; + scissor.offset.x = 0; + scissor.offset.y = 0; + scissor.extent.width = size_x; + scissor.extent.height = size_y; + + vkCmdSetScissor(command_buffer, 0, 1, &scissor); + + return ID_TYPE_DRAW_LIST; +} + +Error RenderingDeviceVulkan::_draw_list_setup_framebuffer(Framebuffer *p_framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, VkFramebuffer *r_framebuffer, VkRenderPass *r_render_pass) { + + Framebuffer::VersionKey vk; + vk.initial_color_action = p_initial_color_action; + vk.final_color_action = p_final_color_action; + vk.initial_depth_action = p_initial_depth_action; + vk.final_depth_action = p_final_depth_action; + + if (!p_framebuffer->framebuffers.has(vk)) { + //need to create this version + Framebuffer::Version version; + + version.render_pass = _render_pass_create(framebuffer_formats[p_framebuffer->format_id].E->key().attachments, p_initial_color_action, p_final_color_action, p_initial_depth_action, p_final_depth_action); + + VkFramebufferCreateInfo framebuffer_create_info; + framebuffer_create_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; + framebuffer_create_info.pNext = NULL; + framebuffer_create_info.flags = 0; + framebuffer_create_info.renderPass = version.render_pass; + Vector<VkImageView> attachments; + for (int i = 0; i < p_framebuffer->texture_ids.size(); i++) { + Texture *texture = texture_owner.getornull(p_framebuffer->texture_ids[i]); + ERR_FAIL_COND_V(!texture, ERR_BUG); + attachments.push_back(texture->view); + ERR_FAIL_COND_V(texture->width != p_framebuffer->size.width, ERR_BUG); + ERR_FAIL_COND_V(texture->height != p_framebuffer->size.height, ERR_BUG); + } + framebuffer_create_info.attachmentCount = attachments.size(); + framebuffer_create_info.pAttachments = attachments.ptr(); + framebuffer_create_info.width = p_framebuffer->size.width; + framebuffer_create_info.height = p_framebuffer->size.height; + framebuffer_create_info.layers = 1; + + VkResult err = vkCreateFramebuffer(device, &framebuffer_create_info, NULL, &version.framebuffer); + ERR_FAIL_COND_V(err, ERR_CANT_CREATE); + + p_framebuffer->framebuffers.insert(vk, version); + } + const Framebuffer::Version &version = p_framebuffer->framebuffers[vk]; + *r_framebuffer = version.framebuffer; + *r_render_pass = version.render_pass; + + return OK; +} + +Error RenderingDeviceVulkan::_draw_list_render_pass_begin(Framebuffer *framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_colors, float p_clear_depth, uint32_t p_clear_stencil, Point2i viewport_offset, Point2i viewport_size, VkFramebuffer vkframebuffer, VkRenderPass render_pass, VkCommandBuffer command_buffer, VkSubpassContents subpass_contents) { + + VkRenderPassBeginInfo render_pass_begin; + render_pass_begin.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; + render_pass_begin.pNext = NULL; + render_pass_begin.renderPass = render_pass; + render_pass_begin.framebuffer = vkframebuffer; + + render_pass_begin.renderArea.extent.width = viewport_size.width; + render_pass_begin.renderArea.extent.height = viewport_size.height; + render_pass_begin.renderArea.offset.x = viewport_offset.x; + render_pass_begin.renderArea.offset.y = viewport_offset.y; + + Vector<VkClearValue> clear_values; + clear_values.resize(framebuffer->texture_ids.size()); + + { + int color_index = 0; + for (int i = 0; i < framebuffer->texture_ids.size(); i++) { + Texture *texture = texture_owner.getornull(framebuffer->texture_ids[i]); + VkClearValue clear_value; + + if (color_index < p_clear_colors.size() && texture->usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) { + ERR_FAIL_INDEX_V(color_index, p_clear_colors.size(), ERR_BUG); //a bug + Color clear_color = p_clear_colors[color_index]; + clear_value.color.float32[0] = clear_color.r; + clear_value.color.float32[1] = clear_color.g; + clear_value.color.float32[2] = clear_color.b; + clear_value.color.float32[3] = clear_color.a; + color_index++; + } else if (texture->usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { + clear_value.depthStencil.depth = p_clear_depth; + clear_value.depthStencil.stencil = p_clear_stencil; + } else { + clear_value.color.float32[0] = 0; + clear_value.color.float32[1] = 0; + clear_value.color.float32[2] = 0; + clear_value.color.float32[3] = 0; + } + clear_values.write[i] = clear_value; + } + } + + render_pass_begin.clearValueCount = clear_values.size(); + render_pass_begin.pClearValues = clear_values.ptr(); + + vkCmdBeginRenderPass(command_buffer, &render_pass_begin, subpass_contents); + + //mark textures as bound + draw_list_bound_textures.clear(); + draw_list_unbind_color_textures = p_final_color_action != FINAL_ACTION_CONTINUE; + draw_list_unbind_depth_textures = p_final_depth_action != FINAL_ACTION_CONTINUE; + + for (int i = 0; i < framebuffer->texture_ids.size(); i++) { + Texture *texture = texture_owner.getornull(framebuffer->texture_ids[i]); + texture->bound = true; + draw_list_bound_textures.push_back(framebuffer->texture_ids[i]); + } + + return OK; +} + +void RenderingDeviceVulkan::_draw_list_insert_clear_region(DrawList *draw_list, Framebuffer *framebuffer, Point2i viewport_offset, Point2i viewport_size, bool p_clear_color, const Vector<Color> &p_clear_colors, bool p_clear_depth, float p_depth, uint32_t p_stencil) { + Vector<VkClearAttachment> clear_attachments; + int color_index = 0; + for (int i = 0; i < framebuffer->texture_ids.size(); i++) { + Texture *texture = texture_owner.getornull(framebuffer->texture_ids[i]); + VkClearAttachment clear_at; + if (p_clear_color && texture->usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) { + ERR_FAIL_INDEX(color_index, p_clear_colors.size()); //a bug + Color clear_color = p_clear_colors[color_index]; + clear_at.clearValue.color.float32[0] = clear_color.r; + clear_at.clearValue.color.float32[1] = clear_color.g; + clear_at.clearValue.color.float32[2] = clear_color.b; + clear_at.clearValue.color.float32[3] = clear_color.a; + clear_at.colorAttachment = color_index++; + clear_at.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + } else if (p_clear_depth && texture->usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { + + clear_at.clearValue.depthStencil.depth = p_depth; + clear_at.clearValue.depthStencil.stencil = p_stencil; + clear_at.colorAttachment = 0; + clear_at.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; + if (format_has_stencil(texture->format)) { + clear_at.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT; + } + } else { + ERR_CONTINUE(true); + } + clear_attachments.push_back(clear_at); + } + + VkClearRect cr; + cr.baseArrayLayer = 0; + cr.layerCount = 1; + cr.rect.offset.x = viewport_offset.x; + cr.rect.offset.y = viewport_offset.y; + cr.rect.extent.width = viewport_size.width; + cr.rect.extent.height = viewport_size.height; + + vkCmdClearAttachments(draw_list->command_buffer, clear_attachments.size(), clear_attachments.ptr(), 1, &cr); +} + +RenderingDevice::DrawListID RenderingDeviceVulkan::draw_list_begin(RID p_framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values, float p_clear_depth, uint32_t p_clear_stencil, const Rect2 &p_region) { + + _THREAD_SAFE_METHOD_ + + ERR_FAIL_COND_V_MSG(draw_list != NULL, INVALID_ID, "Only one draw list can be active at the same time."); + ERR_FAIL_COND_V_MSG(compute_list != NULL, INVALID_ID, "Only one draw/compute list can be active at the same time."); + + Framebuffer *framebuffer = framebuffer_owner.getornull(p_framebuffer); + ERR_FAIL_COND_V(!framebuffer, INVALID_ID); + + Point2i viewport_offset; + Point2i viewport_size = framebuffer->size; + bool needs_clear_color = false; + bool needs_clear_depth = false; + + if (p_region != Rect2() && p_region != Rect2(Vector2(), viewport_size)) { //check custom region + Rect2i viewport(viewport_offset, viewport_size); + Rect2i regioni = p_region; + if (!(regioni.position.x >= viewport.position.x) && (regioni.position.y >= viewport.position.y) && + ((regioni.position.x + regioni.size.x) <= (viewport.position.x + viewport.size.x)) && + ((regioni.position.y + regioni.size.y) <= (viewport.position.y + viewport.size.y))) { + ERR_FAIL_V_MSG(INVALID_ID, "When supplying a custom region, it must be contained within the framebuffer rectangle"); + } + + viewport_offset = regioni.position; + viewport_size = regioni.size; + + if (p_initial_color_action == INITIAL_ACTION_CLEAR) { + needs_clear_color = true; + p_initial_color_action = INITIAL_ACTION_KEEP; + } + if (p_initial_depth_action == INITIAL_ACTION_CLEAR) { + needs_clear_depth = true; + p_initial_depth_action = INITIAL_ACTION_KEEP; + } + } + + if (p_initial_color_action == INITIAL_ACTION_CLEAR) { //check clear values + + int color_attachments = framebuffer_formats[framebuffer->format_id].color_attachments; + ERR_FAIL_COND_V_MSG(p_clear_color_values.size() != color_attachments, INVALID_ID, + "Clear color values supplied (" + itos(p_clear_color_values.size()) + ") differ from the amount required for framebuffer (" + itos(color_attachments) + ")."); + } + + VkFramebuffer vkframebuffer; + VkRenderPass render_pass; + + Error err = _draw_list_setup_framebuffer(framebuffer, p_initial_color_action, p_final_color_action, p_initial_depth_action, p_final_depth_action, &vkframebuffer, &render_pass); + ERR_FAIL_COND_V(err != OK, INVALID_ID); + + VkCommandBuffer command_buffer = frames[frame].draw_command_buffer; + err = _draw_list_render_pass_begin(framebuffer, p_initial_color_action, p_final_color_action, p_initial_depth_action, p_final_depth_action, p_clear_color_values, p_clear_depth, p_clear_stencil, viewport_offset, viewport_size, vkframebuffer, render_pass, command_buffer, VK_SUBPASS_CONTENTS_INLINE); + + if (err != OK) { + return INVALID_ID; + } + + draw_list = memnew(DrawList); + draw_list->command_buffer = command_buffer; +#ifdef DEBUG_ENABLED + draw_list->validation.framebuffer_format = framebuffer->format_id; +#endif + draw_list_count = 0; + draw_list_split = false; + + if (needs_clear_color || needs_clear_depth) { + _draw_list_insert_clear_region(draw_list, framebuffer, viewport_offset, viewport_size, needs_clear_color, p_clear_color_values, needs_clear_depth, p_clear_depth, p_clear_stencil); + } + + VkViewport viewport; + viewport.x = viewport_offset.x; + viewport.y = viewport_offset.y; + viewport.width = viewport_size.width; + viewport.height = viewport_size.height; + viewport.minDepth = 0; + viewport.maxDepth = 1.0; + + vkCmdSetViewport(command_buffer, 0, 1, &viewport); + + VkRect2D scissor; + scissor.offset.x = viewport_offset.x; + scissor.offset.y = viewport_offset.y; + scissor.extent.width = viewport_size.width; + scissor.extent.height = viewport_size.height; + + vkCmdSetScissor(command_buffer, 0, 1, &scissor); + + draw_list->viewport = Rect2i(viewport_offset, viewport_size); + return ID_TYPE_DRAW_LIST; +} + +Error RenderingDeviceVulkan::draw_list_begin_split(RID p_framebuffer, uint32_t p_splits, DrawListID *r_split_ids, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values, float p_clear_depth, uint32_t p_clear_stencil, const Rect2 &p_region) { + + _THREAD_SAFE_METHOD_ + + ERR_FAIL_COND_V(p_splits < 1, ERR_INVALID_DECLARATION); + + Framebuffer *framebuffer = framebuffer_owner.getornull(p_framebuffer); + ERR_FAIL_COND_V(!framebuffer, ERR_INVALID_DECLARATION); + + Point2i viewport_offset; + Point2i viewport_size = framebuffer->size; + + bool needs_clear_color = false; + bool needs_clear_depth = false; + + if (p_region != Rect2() && p_region != Rect2(Vector2(), viewport_size)) { //check custom region + Rect2i viewport(viewport_offset, viewport_size); + Rect2i regioni = p_region; + if (!(regioni.position.x >= viewport.position.x) && (regioni.position.y >= viewport.position.y) && + ((regioni.position.x + regioni.size.x) <= (viewport.position.x + viewport.size.x)) && + ((regioni.position.y + regioni.size.y) <= (viewport.position.y + viewport.size.y))) { + ERR_FAIL_V_MSG(ERR_INVALID_PARAMETER, "When supplying a custom region, it must be contained within the framebuffer rectangle"); + } + + viewport_offset = regioni.position; + viewport_size = regioni.size; + + if (p_initial_color_action == INITIAL_ACTION_CLEAR) { + needs_clear_color = true; + p_initial_color_action = INITIAL_ACTION_KEEP; + } + if (p_initial_depth_action == INITIAL_ACTION_CLEAR) { + needs_clear_depth = true; + p_initial_depth_action = INITIAL_ACTION_KEEP; + } + } + + if (p_initial_color_action == INITIAL_ACTION_CLEAR) { //check clear values + + int color_attachments = framebuffer_formats[framebuffer->format_id].color_attachments; + ERR_FAIL_COND_V_MSG(p_clear_color_values.size() != color_attachments, ERR_INVALID_PARAMETER, + "Clear color values supplied (" + itos(p_clear_color_values.size()) + ") differ from the amount required for framebuffer (" + itos(color_attachments) + ")."); + } + + if (p_splits > (uint32_t)split_draw_list_allocators.size()) { + uint32_t from = split_draw_list_allocators.size(); + split_draw_list_allocators.resize(p_splits); + for (uint32_t i = from; i < p_splits; i++) { + + VkCommandPoolCreateInfo cmd_pool_info; + cmd_pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; + cmd_pool_info.pNext = NULL; + cmd_pool_info.queueFamilyIndex = context->get_graphics_queue(); + cmd_pool_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; + + VkResult res = vkCreateCommandPool(device, &cmd_pool_info, NULL, &split_draw_list_allocators.write[i].command_pool); + ERR_FAIL_COND_V(res, ERR_CANT_CREATE); + + for (int j = 0; j < frame_count; j++) { + + VkCommandBuffer command_buffer; + + VkCommandBufferAllocateInfo cmdbuf; + //no command buffer exists, create it. + cmdbuf.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + cmdbuf.pNext = NULL; + cmdbuf.commandPool = split_draw_list_allocators[i].command_pool; + cmdbuf.level = VK_COMMAND_BUFFER_LEVEL_SECONDARY; + cmdbuf.commandBufferCount = 1; + + VkResult err = vkAllocateCommandBuffers(device, &cmdbuf, &command_buffer); + ERR_FAIL_COND_V(err, ERR_CANT_CREATE); + + split_draw_list_allocators.write[i].command_buffers.push_back(command_buffer); + } + } + } + + VkFramebuffer vkframebuffer; + VkRenderPass render_pass; + + Error err = _draw_list_setup_framebuffer(framebuffer, p_initial_color_action, p_final_color_action, p_initial_depth_action, p_final_depth_action, &vkframebuffer, &render_pass); + ERR_FAIL_COND_V(err != OK, ERR_CANT_CREATE); + + VkCommandBuffer frame_command_buffer = frames[frame].draw_command_buffer; + err = _draw_list_render_pass_begin(framebuffer, p_initial_color_action, p_final_color_action, p_initial_depth_action, p_final_depth_action, p_clear_color_values, p_clear_depth, p_clear_stencil, viewport_offset, viewport_size, vkframebuffer, render_pass, frame_command_buffer, VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS); + + if (err != OK) { + return ERR_CANT_CREATE; + } + + draw_list = memnew_arr(DrawList, p_splits); + draw_list_count = p_splits; + draw_list_split = true; + + for (uint32_t i = 0; i < p_splits; i++) { + + //take a command buffer and initialize it + VkCommandBuffer command_buffer = split_draw_list_allocators[p_splits].command_buffers[frame]; + + VkCommandBufferInheritanceInfo inheritance_info; + inheritance_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO; + inheritance_info.pNext = NULL; + inheritance_info.renderPass = render_pass; + inheritance_info.subpass = 0; + inheritance_info.framebuffer = vkframebuffer; + inheritance_info.occlusionQueryEnable = false; + inheritance_info.queryFlags = 0; //? + inheritance_info.pipelineStatistics = 0; + + VkCommandBufferBeginInfo cmdbuf_begin; + cmdbuf_begin.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + cmdbuf_begin.pNext = NULL; + cmdbuf_begin.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT | VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT; + cmdbuf_begin.pInheritanceInfo = &inheritance_info; + + VkResult res = vkResetCommandBuffer(command_buffer, 0); + if (res) { + memdelete_arr(draw_list); + draw_list = NULL; + ERR_FAIL_V(ERR_CANT_CREATE); + } + + res = vkBeginCommandBuffer(command_buffer, &cmdbuf_begin); + if (res) { + memdelete_arr(draw_list); + draw_list = NULL; + ERR_FAIL_V(ERR_CANT_CREATE); + } + + draw_list[i].command_buffer = command_buffer; +#ifdef DEBUG_ENABLED + draw_list[i].validation.framebuffer_format = framebuffer->format_id; +#endif + + if (i == 0 && (needs_clear_color || needs_clear_depth)) { + _draw_list_insert_clear_region(draw_list, framebuffer, viewport_offset, viewport_size, needs_clear_color, p_clear_color_values, needs_clear_depth, p_clear_depth, p_clear_stencil); + } + + VkViewport viewport; + viewport.x = viewport_offset.x; + viewport.y = viewport_offset.y; + viewport.width = viewport_size.width; + viewport.height = viewport_size.height; + viewport.minDepth = 0; + viewport.maxDepth = 1.0; + + vkCmdSetViewport(command_buffer, 0, 1, &viewport); + + VkRect2D scissor; + scissor.offset.x = viewport_offset.x; + scissor.offset.y = viewport_offset.y; + scissor.extent.width = viewport_size.width; + scissor.extent.height = viewport_size.height; + + vkCmdSetScissor(command_buffer, 0, 1, &scissor); + r_split_ids[i] = (DrawListID(1) << DrawListID(ID_TYPE_SPLIT_DRAW_LIST)) + i; + + draw_list[i].viewport = Rect2i(viewport_offset, viewport_size); + } + + return OK; +} + +RenderingDeviceVulkan::DrawList *RenderingDeviceVulkan::_get_draw_list_ptr(DrawListID p_id) { + + if (p_id < 0) { + return NULL; + } + + if (!draw_list) { + return NULL; + } else if (p_id == ID_TYPE_DRAW_LIST) { + if (draw_list_split) { + return NULL; + } + return draw_list; + } else if (p_id >> DrawListID(ID_BASE_SHIFT) == ID_TYPE_SPLIT_DRAW_LIST) { + if (!draw_list_split) { + return NULL; + } + + uint64_t index = p_id & ((DrawListID(1) << DrawListID(ID_BASE_SHIFT)) - 1); //mask + + if (index >= draw_list_count) { + return NULL; + } + + return &draw_list[index]; + } else { + return NULL; + } +} + +void RenderingDeviceVulkan::draw_list_bind_render_pipeline(DrawListID p_list, RID p_render_pipeline) { + + DrawList *dl = _get_draw_list_ptr(p_list); + ERR_FAIL_COND(!dl); +#ifdef DEBUG_ENABLED + ERR_FAIL_COND_MSG(!dl->validation.active, "Submitted Draw Lists can no longer be modified."); +#endif + + const RenderPipeline *pipeline = render_pipeline_owner.getornull(p_render_pipeline); + ERR_FAIL_COND(!pipeline); +#ifdef DEBUG_ENABLED + ERR_FAIL_COND(pipeline->validation.framebuffer_format != dl->validation.framebuffer_format); +#endif + + if (p_render_pipeline == dl->state.pipeline) { + return; //redundant state, return. + } + + dl->state.pipeline = p_render_pipeline; + dl->state.pipeline_layout = pipeline->pipeline_layout; + + vkCmdBindPipeline(dl->command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->pipeline); + + if (dl->state.pipeline_shader != pipeline->shader) { + // shader changed, so descriptor sets may become incompatible. + + //go through ALL sets, and unbind them (and all those above) if the format is different + + uint32_t pcount = pipeline->set_formats.size(); //formats count in this pipeline + dl->state.set_count = MAX(dl->state.set_count, pcount); + const uint32_t *pformats = pipeline->set_formats.ptr(); //pipeline set formats + + bool sets_valid = true; //once invalid, all above become invalid + for (uint32_t i = 0; i < pcount; i++) { + //if a part of the format is different, invalidate it (and the rest) + if (!sets_valid || dl->state.sets[i].pipeline_expected_format != pformats[i]) { + dl->state.sets[i].bound = false; + dl->state.sets[i].pipeline_expected_format = pformats[i]; + sets_valid = false; + } + } + + for (uint32_t i = pcount; i < dl->state.set_count; i++) { + //unbind the ones above (not used) if exist + dl->state.sets[i].bound = false; + } + + dl->state.set_count = pcount; //update set count + + if (pipeline->push_constant_size) { + dl->state.pipeline_push_constant_stages = pipeline->push_constant_stages; +#ifdef DEBUG_ENABLED + dl->validation.pipeline_push_constant_suppplied = false; +#endif + } + + dl->state.pipeline_shader = pipeline->shader; + } + +#ifdef DEBUG_ENABLED + //update render pass pipeline info + dl->validation.pipeline_active = true; + dl->validation.pipeline_dynamic_state = pipeline->validation.dynamic_state; + dl->validation.pipeline_vertex_format = pipeline->validation.vertex_format; + dl->validation.pipeline_uses_restart_indices = pipeline->validation.uses_restart_indices; + dl->validation.pipeline_primitive_divisor = pipeline->validation.primitive_divisor; + dl->validation.pipeline_primitive_minimum = pipeline->validation.primitive_minimum; + dl->validation.pipeline_push_constant_size = pipeline->push_constant_size; +#endif +} + +void RenderingDeviceVulkan::draw_list_bind_uniform_set(DrawListID p_list, RID p_uniform_set, uint32_t p_index) { + +#ifdef DEBUG_ENABLED + ERR_FAIL_COND_MSG(p_index >= limits.maxBoundDescriptorSets || p_index > MAX_UNIFORM_SETS, + "Attempting to bind a descriptor set (" + itos(p_index) + ") greater than what the hardware supports (" + itos(limits.maxBoundDescriptorSets) + ")."); +#endif + DrawList *dl = _get_draw_list_ptr(p_list); + ERR_FAIL_COND(!dl); + +#ifdef DEBUG_ENABLED + ERR_FAIL_COND_MSG(!dl->validation.active, "Submitted Draw Lists can no longer be modified."); +#endif + + const UniformSet *uniform_set = uniform_set_owner.getornull(p_uniform_set); + ERR_FAIL_COND(!uniform_set); + + if (p_index > dl->state.set_count) { + dl->state.set_count = p_index; + } + + dl->state.sets[p_index].descriptor_set = uniform_set->descriptor_set; //update set pointer + dl->state.sets[p_index].bound = false; //needs rebind + dl->state.sets[p_index].uniform_set_format = uniform_set->format; + dl->state.sets[p_index].uniform_set = p_uniform_set; + +#ifdef DEBUG_ENABLED + { //validate that textures bound are not attached as framebuffer bindings + uint32_t attachable_count = uniform_set->attachable_textures.size(); + const RID *attachable_ptr = uniform_set->attachable_textures.ptr(); + uint32_t bound_count = draw_list_bound_textures.size(); + const RID *bound_ptr = draw_list_bound_textures.ptr(); + for (uint32_t i = 0; i < attachable_count; i++) { + for (uint32_t j = 0; j < bound_count; j++) { + ERR_FAIL_COND_MSG(attachable_ptr[i] == bound_ptr[j], + "Attempted to use the same texture in framebuffer attachment and a uniform set, this is not allowed."); + } + } + } +#endif +} + +void RenderingDeviceVulkan::draw_list_bind_vertex_array(DrawListID p_list, RID p_vertex_array) { + DrawList *dl = _get_draw_list_ptr(p_list); + ERR_FAIL_COND(!dl); +#ifdef DEBUG_ENABLED + ERR_FAIL_COND_MSG(!dl->validation.active, "Submitted Draw Lists can no longer be modified."); +#endif + + const VertexArray *vertex_array = vertex_array_owner.getornull(p_vertex_array); + ERR_FAIL_COND(!vertex_array); + + if (dl->state.vertex_array == p_vertex_array) { + return; //already set + } + + dl->state.vertex_array = p_vertex_array; + +#ifdef DEBUG_ENABLED + dl->validation.vertex_format = vertex_array->description; + dl->validation.vertex_max_instances_allowed = vertex_array->max_instances_allowed; +#endif + dl->validation.vertex_array_size = vertex_array->vertex_count; + vkCmdBindVertexBuffers(dl->command_buffer, 0, vertex_array->buffers.size(), vertex_array->buffers.ptr(), vertex_array->offsets.ptr()); +} +void RenderingDeviceVulkan::draw_list_bind_index_array(DrawListID p_list, RID p_index_array) { + + DrawList *dl = _get_draw_list_ptr(p_list); + ERR_FAIL_COND(!dl); +#ifdef DEBUG_ENABLED + ERR_FAIL_COND_MSG(!dl->validation.active, "Submitted Draw Lists can no longer be modified."); +#endif + + const IndexArray *index_array = index_array_owner.getornull(p_index_array); + ERR_FAIL_COND(!index_array); + + if (dl->state.index_array == p_index_array) { + return; //already set + } + + dl->state.index_array = p_index_array; +#ifdef DEBUG_ENABLED + dl->validation.index_array_max_index = index_array->max_index; +#endif + dl->validation.index_array_size = index_array->indices; + dl->validation.index_array_offset = index_array->offset; + + vkCmdBindIndexBuffer(dl->command_buffer, index_array->buffer, index_array->offset, index_array->index_type); +} + +void RenderingDeviceVulkan::draw_list_set_line_width(DrawListID p_list, float p_width) { + + DrawList *dl = _get_draw_list_ptr(p_list); + ERR_FAIL_COND(!dl); +#ifdef DEBUG_ENABLED + ERR_FAIL_COND_MSG(!dl->validation.active, "Submitted Draw Lists can no longer be modified."); +#endif + + vkCmdSetLineWidth(dl->command_buffer, p_width); +} + +void RenderingDeviceVulkan::draw_list_set_push_constant(DrawListID p_list, void *p_data, uint32_t p_data_size) { + DrawList *dl = _get_draw_list_ptr(p_list); + ERR_FAIL_COND(!dl); + +#ifdef DEBUG_ENABLED + ERR_FAIL_COND_MSG(!dl->validation.active, "Submitted Draw Lists can no longer be modified."); +#endif + +#ifdef DEBUG_ENABLED + ERR_FAIL_COND_MSG(p_data_size != dl->validation.pipeline_push_constant_size, + "This render pipeline requires (" + itos(dl->validation.pipeline_push_constant_size) + ") bytes of push constant data, supplied: (" + itos(p_data_size) + ")"); +#endif + vkCmdPushConstants(dl->command_buffer, dl->state.pipeline_layout, dl->state.pipeline_push_constant_stages, 0, p_data_size, p_data); +#ifdef DEBUG_ENABLED + dl->validation.pipeline_push_constant_suppplied = true; +#endif +} + +void RenderingDeviceVulkan::draw_list_draw(DrawListID p_list, bool p_use_indices, uint32_t p_instances, uint32_t p_procedural_vertices) { + + DrawList *dl = _get_draw_list_ptr(p_list); + ERR_FAIL_COND(!dl); +#ifdef DEBUG_ENABLED + ERR_FAIL_COND_MSG(!dl->validation.active, "Submitted Draw Lists can no longer be modified."); +#endif + +#ifdef DEBUG_ENABLED + ERR_FAIL_COND_MSG(!dl->validation.pipeline_active, + "No render pipeline was set before attempting to draw."); + if (dl->validation.pipeline_vertex_format != INVALID_ID) { + //pipeline uses vertices, validate format + ERR_FAIL_COND_MSG(dl->validation.vertex_format == INVALID_ID, + "No vertex array was bound, and render pipeline expects vertices."); + //make sure format is right + ERR_FAIL_COND_MSG(dl->validation.pipeline_vertex_format != dl->validation.vertex_format, + "The vertex format used to create the pipeline does not match the vertex format bound."); + //make sure amount of instances is valid + ERR_FAIL_COND_MSG(p_instances > dl->validation.vertex_max_instances_allowed, + "Amount of instances requested (" + itos(p_instances) + " is larger than the maximum amount suported by the bound vertex array (" + itos(dl->validation.vertex_max_instances_allowed) + ")."); + } + + if (dl->validation.pipeline_push_constant_size > 0) { + //using push constants, check that they were supplied + ERR_FAIL_COND_MSG(!dl->validation.pipeline_push_constant_suppplied, + "The shader in this pipeline requires a push constant to be set before drawing, but it's not present."); + } + +#endif + + //Bind descriptor sets + + for (uint32_t i = 0; i < dl->state.set_count; i++) { + + if (dl->state.sets[i].pipeline_expected_format == 0) { + continue; //nothing expected by this pipeline + } +#ifdef DEBUG_ENABLED + if (dl->state.sets[i].pipeline_expected_format != dl->state.sets[i].uniform_set_format) { + + if (dl->state.sets[i].uniform_set_format == 0) { + ERR_FAIL_MSG("Uniforms were never supplied for set (" + itos(i) + ") at the time of drawing, which are required by the pipeline"); + } else if (uniform_set_owner.owns(dl->state.sets[i].uniform_set)) { + UniformSet *us = uniform_set_owner.getornull(dl->state.sets[i].uniform_set); + ERR_FAIL_MSG("Uniforms supplied for set (" + itos(i) + "):\n" + _shader_uniform_debug(us->shader_id, us->shader_set) + "\nare not the same format as required by the pipeline shader. Pipeline shader requires the following bindings:\n" + _shader_uniform_debug(dl->state.pipeline_shader)); + } else { + ERR_FAIL_MSG("Uniforms supplied for set (" + itos(i) + ", which was was just freed) are not the same format as required by the pipeline shader. Pipeline shader requires the following bindings:\n" + _shader_uniform_debug(dl->state.pipeline_shader)); + } + } +#endif + if (!dl->state.sets[i].bound) { + //All good, see if this requires re-binding + vkCmdBindDescriptorSets(dl->command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, dl->state.pipeline_layout, i, 1, &dl->state.sets[i].descriptor_set, 0, NULL); + dl->state.sets[i].bound = true; + } + } + + if (p_use_indices) { + +#ifdef DEBUG_ENABLED + ERR_FAIL_COND_MSG(p_procedural_vertices > 0, + "Procedural vertices can't be used together with indices."); + + ERR_FAIL_COND_MSG(!dl->validation.index_array_size, + "Draw command requested indices, but no index buffer was set."); + + if (dl->validation.pipeline_vertex_format != INVALID_ID) { + //uses vertices, do some vertex validations + ERR_FAIL_COND_MSG(dl->validation.vertex_array_size < dl->validation.index_array_max_index, + "Index array references (max index: " + itos(dl->validation.index_array_max_index) + ") indices beyond the vertex array size (" + itos(dl->validation.vertex_array_size) + ")."); + } + + ERR_FAIL_COND_MSG(dl->validation.pipeline_uses_restart_indices != dl->validation.index_buffer_uses_restart_indices, + "The usage of restart indices in index buffer does not match the render primitive in the pipeline."); +#endif + uint32_t to_draw = dl->validation.index_array_size; + +#ifdef DEBUG_ENABLED + ERR_FAIL_COND_MSG(to_draw < dl->validation.pipeline_primitive_minimum, + "Too few indices (" + itos(to_draw) + ") for the render primitive set in the render pipeline (" + itos(dl->validation.pipeline_primitive_minimum) + ")."); + + ERR_FAIL_COND_MSG((to_draw % dl->validation.pipeline_primitive_divisor) != 0, + "Index amount (" + itos(to_draw) + ") must be a multiple of the amount of indices required by the render primitive (" + itos(dl->validation.pipeline_primitive_divisor) + ")."); +#endif + vkCmdDrawIndexed(dl->command_buffer, to_draw, p_instances, dl->validation.index_array_offset, 0, 0); + } else { + + uint32_t to_draw; + + if (p_procedural_vertices > 0) { +#ifdef DEBUG_ENABLED + ERR_FAIL_COND_MSG(dl->validation.pipeline_vertex_format == INVALID_ID, + "Procedural vertices requested, but pipeline expects a vertex array."); +#endif + to_draw = p_procedural_vertices; + } else { + +#ifdef DEBUG_ENABLED + ERR_FAIL_COND_MSG(dl->validation.pipeline_vertex_format == INVALID_ID, + "Draw command lacks indices, but pipeline format does not use vertices."); +#endif + to_draw = dl->validation.vertex_array_size; + } + +#ifdef DEBUG_ENABLED + ERR_FAIL_COND_MSG(to_draw < dl->validation.pipeline_primitive_minimum, + "Too few vertices (" + itos(to_draw) + ") for the render primitive set in the render pipeline (" + itos(dl->validation.pipeline_primitive_minimum) + ")."); + + ERR_FAIL_COND_MSG((to_draw % dl->validation.pipeline_primitive_divisor) != 0, + "Vertex amount (" + itos(to_draw) + ") must be a multiple of the amount of vertices required by the render primitive (" + itos(dl->validation.pipeline_primitive_divisor) + ")."); +#endif + + vkCmdDraw(dl->command_buffer, to_draw, p_instances, 0, 0); + } +} + +void RenderingDeviceVulkan::draw_list_enable_scissor(DrawListID p_list, const Rect2 &p_rect) { + DrawList *dl = _get_draw_list_ptr(p_list); + + ERR_FAIL_COND(!dl); +#ifdef DEBUG_ENABLED + ERR_FAIL_COND_MSG(!dl->validation.active, "Submitted Draw Lists can no longer be modified."); +#endif + Rect2i rect = p_rect; + rect.position += dl->viewport.position; + + rect = dl->viewport.clip(rect); + + if (rect.get_area() == 0) { + return; + } + VkRect2D scissor; + scissor.offset.x = rect.position.x; + scissor.offset.y = rect.position.y; + scissor.extent.width = rect.size.width; + scissor.extent.height = rect.size.height; + + vkCmdSetScissor(dl->command_buffer, 0, 1, &scissor); +} +void RenderingDeviceVulkan::draw_list_disable_scissor(DrawListID p_list) { + DrawList *dl = _get_draw_list_ptr(p_list); + ERR_FAIL_COND(!dl); +#ifdef DEBUG_ENABLED + ERR_FAIL_COND_MSG(!dl->validation.active, "Submitted Draw Lists can no longer be modified."); +#endif + + VkRect2D scissor; + scissor.offset.x = dl->viewport.position.x; + scissor.offset.y = dl->viewport.position.y; + scissor.extent.width = dl->viewport.size.width; + scissor.extent.height = dl->viewport.size.height; + vkCmdSetScissor(dl->command_buffer, 0, 1, &scissor); +} + +void RenderingDeviceVulkan::draw_list_end() { + + _THREAD_SAFE_METHOD_ + + ERR_FAIL_COND_MSG(!draw_list, "Immediate draw list is already inactive."); + + if (draw_list_split) { + //send all command buffers + VkCommandBuffer *command_buffers = (VkCommandBuffer *)alloca(sizeof(VkCommandBuffer) * draw_list_count); + for (uint32_t i = 0; i < draw_list_count; i++) { + vkEndCommandBuffer(draw_list->command_buffer); + command_buffers[i] = draw_list->command_buffer; + } + + vkCmdExecuteCommands(frames[frame].draw_command_buffer, draw_list_count, command_buffers); + vkCmdEndRenderPass(frames[frame].draw_command_buffer); + memdelete_arr(draw_list); + draw_list = NULL; + + } else { + //just end the list + vkCmdEndRenderPass(draw_list->command_buffer); + memdelete(draw_list); + draw_list = NULL; + } + + for (int i = 0; i < draw_list_bound_textures.size(); i++) { + Texture *texture = texture_owner.getornull(draw_list_bound_textures[i]); + ERR_CONTINUE(!texture); //wtf + if (draw_list_unbind_color_textures && (texture->usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT)) { + texture->bound = false; + } + if (draw_list_unbind_depth_textures && (texture->usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) { + texture->bound = false; + } + } + + draw_list_bound_textures.clear(); + + // To ensure proper synchronization, we must make sure rendering is done before: + // * Some buffer is copied + // * Another render pass happens (since we may be done + +#ifdef FORCE_FULL_BARRIER + _full_barrier(true); +#else + _memory_barrier(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, VK_PIPELINE_STAGE_VERTEX_INPUT_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_INDEX_READ_BIT | VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT | VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT, true); +#endif +} + +/***********************/ +/**** COMPUTE LISTS ****/ +/***********************/ + +RenderingDevice::ComputeListID RenderingDeviceVulkan::compute_list_begin() { + + ERR_FAIL_COND_V_MSG(draw_list != NULL, INVALID_ID, "Only one draw list can be active at the same time."); + ERR_FAIL_COND_V_MSG(compute_list != NULL, INVALID_ID, "Only one draw/compute list can be active at the same time."); + + compute_list = memnew(ComputeList); + compute_list->command_buffer = frames[frame].draw_command_buffer; + + return ID_TYPE_COMPUTE_LIST; +} + +void RenderingDeviceVulkan::compute_list_bind_compute_pipeline(ComputeListID p_list, RID p_compute_pipeline) { + ERR_FAIL_COND(p_list != ID_TYPE_COMPUTE_LIST); + ERR_FAIL_COND(!compute_list); + + ComputeList *cl = compute_list; + + const ComputePipeline *pipeline = compute_pipeline_owner.getornull(p_compute_pipeline); + ERR_FAIL_COND(!pipeline); + + if (p_compute_pipeline == cl->state.pipeline) { + return; //redundant state, return. + } + + cl->state.pipeline = p_compute_pipeline; + cl->state.pipeline_layout = pipeline->pipeline_layout; + + vkCmdBindPipeline(cl->command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline->pipeline); + + if (cl->state.pipeline_shader != pipeline->shader) { + // shader changed, so descriptor sets may become incompatible. + + //go through ALL sets, and unbind them (and all those above) if the format is different + + uint32_t pcount = pipeline->set_formats.size(); //formats count in this pipeline + cl->state.set_count = MAX(cl->state.set_count, pcount); + const uint32_t *pformats = pipeline->set_formats.ptr(); //pipeline set formats + + bool sets_valid = true; //once invalid, all above become invalid + for (uint32_t i = 0; i < pcount; i++) { + //if a part of the format is different, invalidate it (and the rest) + if (!sets_valid || cl->state.sets[i].pipeline_expected_format != pformats[i]) { + cl->state.sets[i].bound = false; + cl->state.sets[i].pipeline_expected_format = pformats[i]; + sets_valid = false; + } + } + + for (uint32_t i = pcount; i < cl->state.set_count; i++) { + //unbind the ones above (not used) if exist + cl->state.sets[i].bound = false; + } + + cl->state.set_count = pcount; //update set count + + if (pipeline->push_constant_size) { + cl->state.pipeline_push_constant_stages = pipeline->push_constant_stages; +#ifdef DEBUG_ENABLED + cl->validation.pipeline_push_constant_suppplied = false; +#endif + } + + cl->state.pipeline_shader = pipeline->shader; + } + +#ifdef DEBUG_ENABLED + //update compute pass pipeline info + cl->validation.pipeline_active = true; + cl->validation.pipeline_push_constant_size = pipeline->push_constant_size; +#endif +} +void RenderingDeviceVulkan::compute_list_bind_uniform_set(ComputeListID p_list, RID p_uniform_set, uint32_t p_index) { + ERR_FAIL_COND(p_list != ID_TYPE_COMPUTE_LIST); + ERR_FAIL_COND(!compute_list); + + ComputeList *cl = compute_list; + +#ifdef DEBUG_ENABLED + ERR_FAIL_COND_MSG(p_index >= limits.maxBoundDescriptorSets || p_index > MAX_UNIFORM_SETS, + "Attempting to bind a descriptor set (" + itos(p_index) + ") greater than what the hardware supports (" + itos(limits.maxBoundDescriptorSets) + ")."); +#endif + +#ifdef DEBUG_ENABLED + ERR_FAIL_COND_MSG(!cl->validation.active, "Submitted Compute Lists can no longer be modified."); +#endif + + UniformSet *uniform_set = uniform_set_owner.getornull(p_uniform_set); + ERR_FAIL_COND(!uniform_set); + + if (p_index > cl->state.set_count) { + cl->state.set_count = p_index; + } + + cl->state.sets[p_index].descriptor_set = uniform_set->descriptor_set; //update set pointer + cl->state.sets[p_index].bound = false; //needs rebind + cl->state.sets[p_index].uniform_set_format = uniform_set->format; + cl->state.sets[p_index].uniform_set = p_uniform_set; + + uint32_t textures_to_sampled_count = uniform_set->mutable_sampled_textures.size(); + Texture **textures_to_sampled = uniform_set->mutable_sampled_textures.ptrw(); + + for (uint32_t i = 0; i < textures_to_sampled_count; i++) { + if (textures_to_sampled[i]->layout != VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) { + + VkImageMemoryBarrier image_memory_barrier; + image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + image_memory_barrier.pNext = NULL; + image_memory_barrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; + image_memory_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; + image_memory_barrier.oldLayout = textures_to_sampled[i]->layout; + image_memory_barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + + image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + image_memory_barrier.image = textures_to_sampled[i]->image; + image_memory_barrier.subresourceRange.aspectMask = textures_to_sampled[i]->read_aspect_mask; + image_memory_barrier.subresourceRange.baseMipLevel = 0; + image_memory_barrier.subresourceRange.levelCount = textures_to_sampled[i]->mipmaps; + image_memory_barrier.subresourceRange.baseArrayLayer = 0; + image_memory_barrier.subresourceRange.layerCount = textures_to_sampled[i]->layers; + + vkCmdPipelineBarrier(cl->command_buffer, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, NULL, 0, NULL, 1, &image_memory_barrier); + + textures_to_sampled[i]->layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + + cl->state.textures_to_sampled_layout.erase(textures_to_sampled[i]); + } + } + + uint32_t textures_to_storage_count = uniform_set->mutable_storage_textures.size(); + Texture **textures_to_storage = uniform_set->mutable_storage_textures.ptrw(); + + for (uint32_t i = 0; i < textures_to_storage_count; i++) { + if (textures_to_storage[i]->layout != VK_IMAGE_LAYOUT_GENERAL) { + + VkImageMemoryBarrier image_memory_barrier; + image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + image_memory_barrier.pNext = NULL; + image_memory_barrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; + image_memory_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; + image_memory_barrier.oldLayout = textures_to_storage[i]->layout; + image_memory_barrier.newLayout = VK_IMAGE_LAYOUT_GENERAL; + + image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + image_memory_barrier.image = textures_to_storage[i]->image; + image_memory_barrier.subresourceRange.aspectMask = textures_to_storage[i]->read_aspect_mask; + image_memory_barrier.subresourceRange.baseMipLevel = 0; + image_memory_barrier.subresourceRange.levelCount = textures_to_storage[i]->mipmaps; + image_memory_barrier.subresourceRange.baseArrayLayer = 0; + image_memory_barrier.subresourceRange.layerCount = textures_to_storage[i]->layers; + + vkCmdPipelineBarrier(cl->command_buffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, NULL, 0, NULL, 1, &image_memory_barrier); + + textures_to_storage[i]->layout = VK_IMAGE_LAYOUT_GENERAL; + + cl->state.textures_to_sampled_layout.insert(textures_to_storage[i]); //needs to go back to sampled layout afterwards + } + } + +#if 0 + { //validate that textures bound are not attached as framebuffer bindings + uint32_t attachable_count = uniform_set->attachable_textures.size(); + const RID *attachable_ptr = uniform_set->attachable_textures.ptr(); + uint32_t bound_count = draw_list_bound_textures.size(); + const RID *bound_ptr = draw_list_bound_textures.ptr(); + for (uint32_t i = 0; i < attachable_count; i++) { + for (uint32_t j = 0; j < bound_count; j++) { + ERR_FAIL_COND_MSG(attachable_ptr[i] == bound_ptr[j], + "Attempted to use the same texture in framebuffer attachment and a uniform set, this is not allowed."); + } + } + } +#endif +} + +void RenderingDeviceVulkan::compute_list_set_push_constant(ComputeListID p_list, void *p_data, uint32_t p_data_size) { + ERR_FAIL_COND(p_list != ID_TYPE_COMPUTE_LIST); + ERR_FAIL_COND(!compute_list); + + ComputeList *cl = compute_list; + +#ifdef DEBUG_ENABLED + ERR_FAIL_COND_MSG(!cl->validation.active, "Submitted Compute Lists can no longer be modified."); +#endif + +#ifdef DEBUG_ENABLED + ERR_FAIL_COND_MSG(p_data_size != cl->validation.pipeline_push_constant_size, + "This compute pipeline requires (" + itos(cl->validation.pipeline_push_constant_size) + ") bytes of push constant data, supplied: (" + itos(p_data_size) + ")"); +#endif + vkCmdPushConstants(cl->command_buffer, cl->state.pipeline_layout, cl->state.pipeline_push_constant_stages, 0, p_data_size, p_data); +#ifdef DEBUG_ENABLED + cl->validation.pipeline_push_constant_suppplied = true; +#endif +} +void RenderingDeviceVulkan::compute_list_dispatch(ComputeListID p_list, uint32_t p_x_groups, uint32_t p_y_groups, uint32_t p_z_groups) { + ERR_FAIL_COND(p_list != ID_TYPE_COMPUTE_LIST); + ERR_FAIL_COND(!compute_list); + + ComputeList *cl = compute_list; + +#ifdef DEBUG_ENABLED + ERR_FAIL_COND_MSG(p_x_groups > limits.maxComputeWorkGroupCount[0], + "Dispatch amount of X compute groups (" + itos(p_x_groups) + ") is larger than device limit (" + itos(limits.maxComputeWorkGroupCount[0]) + ")"); + ERR_FAIL_COND_MSG(p_y_groups > limits.maxComputeWorkGroupCount[1], + "Dispatch amount of Y compute groups (" + itos(p_x_groups) + ") is larger than device limit (" + itos(limits.maxComputeWorkGroupCount[0]) + ")"); + ERR_FAIL_COND_MSG(p_z_groups > limits.maxComputeWorkGroupCount[2], + "Dispatch amount of Z compute groups (" + itos(p_x_groups) + ") is larger than device limit (" + itos(limits.maxComputeWorkGroupCount[0]) + ")"); + + ERR_FAIL_COND_MSG(!cl->validation.active, "Submitted Compute Lists can no longer be modified."); +#endif + +#ifdef DEBUG_ENABLED + + ERR_FAIL_COND_MSG(!cl->validation.pipeline_active, "No compute pipeline was set before attempting to draw."); + + if (cl->validation.pipeline_push_constant_size > 0) { + //using push constants, check that they were supplied + ERR_FAIL_COND_MSG(!cl->validation.pipeline_push_constant_suppplied, + "The shader in this pipeline requires a push constant to be set before drawing, but it's not present."); + } + +#endif + + //Bind descriptor sets + + for (uint32_t i = 0; i < cl->state.set_count; i++) { + + if (cl->state.sets[i].pipeline_expected_format == 0) { + continue; //nothing expected by this pipeline + } +#ifdef DEBUG_ENABLED + if (cl->state.sets[i].pipeline_expected_format != cl->state.sets[i].uniform_set_format) { + + if (cl->state.sets[i].uniform_set_format == 0) { + ERR_FAIL_MSG("Uniforms were never supplied for set (" + itos(i) + ") at the time of drawing, which are required by the pipeline"); + } else if (uniform_set_owner.owns(cl->state.sets[i].uniform_set)) { + UniformSet *us = uniform_set_owner.getornull(cl->state.sets[i].uniform_set); + ERR_FAIL_MSG("Uniforms supplied for set (" + itos(i) + "):\n" + _shader_uniform_debug(us->shader_id, us->shader_set) + "\nare not the same format as required by the pipeline shader. Pipeline shader requires the following bindings:\n" + _shader_uniform_debug(cl->state.pipeline_shader)); + } else { + ERR_FAIL_MSG("Uniforms supplied for set (" + itos(i) + ", which was was just freed) are not the same format as required by the pipeline shader. Pipeline shader requires the following bindings:\n" + _shader_uniform_debug(cl->state.pipeline_shader)); + } + } +#endif + if (!cl->state.sets[i].bound) { + //All good, see if this requires re-binding + vkCmdBindDescriptorSets(cl->command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, cl->state.pipeline_layout, i, 1, &cl->state.sets[i].descriptor_set, 0, NULL); + cl->state.sets[i].bound = true; + } + } + + vkCmdDispatch(cl->command_buffer, p_x_groups, p_y_groups, p_z_groups); +} + +void RenderingDeviceVulkan::compute_list_add_barrier(ComputeListID p_list) { +#ifdef FORCE_FULL_BARRIER + _full_barrier(true); +#else + _memory_barrier(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, true); +#endif +} + +void RenderingDeviceVulkan::compute_list_end() { + ERR_FAIL_COND(!compute_list); + + for (Set<Texture *>::Element *E = compute_list->state.textures_to_sampled_layout.front(); E; E = E->next()) { + + VkImageMemoryBarrier image_memory_barrier; + image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + image_memory_barrier.pNext = NULL; + image_memory_barrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; + image_memory_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + image_memory_barrier.oldLayout = E->get()->layout; + image_memory_barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + + image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + image_memory_barrier.image = E->get()->image; + image_memory_barrier.subresourceRange.aspectMask = E->get()->read_aspect_mask; + image_memory_barrier.subresourceRange.baseMipLevel = 0; + image_memory_barrier.subresourceRange.levelCount = E->get()->mipmaps; + image_memory_barrier.subresourceRange.baseArrayLayer = 0; + image_memory_barrier.subresourceRange.layerCount = E->get()->layers; + + vkCmdPipelineBarrier(compute_list->command_buffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, NULL, 0, NULL, 1, &image_memory_barrier); + + E->get()->layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + } + + memdelete(compute_list); + compute_list = NULL; +#ifdef FORCE_FULL_BARRIER + _full_barrier(true); +#else + _memory_barrier(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_VERTEX_INPUT_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_SHADER_WRITE_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | VK_ACCESS_INDEX_READ_BIT | VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT | VK_ACCESS_TRANSFER_READ_BIT, true); +#endif +} + +#if 0 +void RenderingDeviceVulkan::draw_list_render_secondary_to_framebuffer(ID p_framebuffer, ID *p_draw_lists, uint32_t p_draw_list_count, InitialAction p_initial_action, FinalAction p_final_action, const Vector<Variant> &p_clear_colors) { + + VkCommandBuffer frame_cmdbuf = frames[frame].frame_buffer; + ERR_FAIL_COND(!frame_cmdbuf); + + VkRenderPassBeginInfo render_pass_begin; + render_pass_begin.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; + render_pass_begin.pNext = NULL; + render_pass_begin.renderPass = context->get_render_pass(); + render_pass_begin.framebuffer = context->get_frame_framebuffer(frame); + + render_pass_begin.renderArea.extent.width = context->get_screen_width(p_screen); + render_pass_begin.renderArea.extent.height = context->get_screen_height(p_screen); + render_pass_begin.renderArea.offset.x = 0; + render_pass_begin.renderArea.offset.y = 0; + + render_pass_begin.clearValueCount = 1; + + VkClearValue clear_value; + clear_value.color.float32[0] = p_clear_color.r; + clear_value.color.float32[1] = p_clear_color.g; + clear_value.color.float32[2] = p_clear_color.b; + clear_value.color.float32[3] = p_clear_color.a; + + render_pass_begin.pClearValues = &clear_value; + + vkCmdBeginRenderPass(frame_cmdbuf, &render_pass_begin, VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS); + + ID screen_format = screen_get_framebuffer_format(); + { + + VkCommandBuffer *command_buffers = (VkCommandBuffer *)alloca(sizeof(VkCommandBuffer) * p_draw_list_count); + uint32_t command_buffer_count = 0; + + for (uint32_t i = 0; i < p_draw_list_count; i++) { + DrawList *dl = _get_draw_list_ptr(p_draw_lists[i]); + ERR_CONTINUE_MSG(!dl, "Draw list index (" + itos(i) + ") is not a valid draw list ID."); + ERR_CONTINUE_MSG(dl->validation.framebuffer_format != p_format_check, + "Draw list index (" + itos(i) + ") is created with a framebuffer format incompatible with this render pass."); + + if (dl->validation.active) { + //needs to be closed, so close it. + vkEndCommandBuffer(dl->command_buffer); + dl->validation.active = false; + } + + command_buffers[command_buffer_count++] = dl->command_buffer; + } + + print_line("to draw: " + itos(command_buffer_count)); + vkCmdExecuteCommands(p_primary, command_buffer_count, command_buffers); + } + + vkCmdEndRenderPass(frame_cmdbuf); + +} +#endif + +void RenderingDeviceVulkan::_free_internal(RID p_id) { + + //push everything so it's disposed of next time this frame index is processed (means, it's safe to do it) + if (texture_owner.owns(p_id)) { + Texture *texture = texture_owner.getornull(p_id); + frames[frame].textures_to_dispose_of.push_back(*texture); + texture_owner.free(p_id); + } else if (framebuffer_owner.owns(p_id)) { + Framebuffer *framebuffer = framebuffer_owner.getornull(p_id); + frames[frame].framebuffers_to_dispose_of.push_back(*framebuffer); + framebuffer_owner.free(p_id); + } else if (sampler_owner.owns(p_id)) { + VkSampler *sampler = sampler_owner.getornull(p_id); + frames[frame].samplers_to_dispose_of.push_back(*sampler); + sampler_owner.free(p_id); + } else if (vertex_buffer_owner.owns(p_id)) { + Buffer *vertex_buffer = vertex_buffer_owner.getornull(p_id); + frames[frame].buffers_to_dispose_of.push_back(*vertex_buffer); + vertex_buffer_owner.free(p_id); + } else if (vertex_array_owner.owns(p_id)) { + vertex_array_owner.free(p_id); + } else if (index_buffer_owner.owns(p_id)) { + IndexBuffer *index_buffer = index_buffer_owner.getornull(p_id); + Buffer b; + b.allocation = index_buffer->allocation; + b.buffer = index_buffer->buffer; + b.size = index_buffer->size; + frames[frame].buffers_to_dispose_of.push_back(b); + index_buffer_owner.free(p_id); + } else if (index_array_owner.owns(p_id)) { + index_array_owner.free(p_id); + } else if (shader_owner.owns(p_id)) { + Shader *shader = shader_owner.getornull(p_id); + frames[frame].shaders_to_dispose_of.push_back(*shader); + shader_owner.free(p_id); + } else if (uniform_buffer_owner.owns(p_id)) { + Buffer *uniform_buffer = uniform_buffer_owner.getornull(p_id); + frames[frame].buffers_to_dispose_of.push_back(*uniform_buffer); + uniform_buffer_owner.free(p_id); + } else if (texture_buffer_owner.owns(p_id)) { + TextureBuffer *texture_buffer = texture_buffer_owner.getornull(p_id); + frames[frame].buffers_to_dispose_of.push_back(texture_buffer->buffer); + frames[frame].buffer_views_to_dispose_of.push_back(texture_buffer->view); + texture_buffer_owner.free(p_id); + } else if (storage_buffer_owner.owns(p_id)) { + Buffer *storage_buffer = storage_buffer_owner.getornull(p_id); + frames[frame].buffers_to_dispose_of.push_back(*storage_buffer); + storage_buffer_owner.free(p_id); + } else if (uniform_set_owner.owns(p_id)) { + UniformSet *uniform_set = uniform_set_owner.getornull(p_id); + frames[frame].uniform_sets_to_dispose_of.push_back(*uniform_set); + uniform_set_owner.free(p_id); + } else if (render_pipeline_owner.owns(p_id)) { + RenderPipeline *pipeline = render_pipeline_owner.getornull(p_id); + frames[frame].render_pipelines_to_dispose_of.push_back(*pipeline); + render_pipeline_owner.free(p_id); + } else if (compute_pipeline_owner.owns(p_id)) { + ComputePipeline *pipeline = compute_pipeline_owner.getornull(p_id); + frames[frame].compute_pipelines_to_dispose_of.push_back(*pipeline); + compute_pipeline_owner.free(p_id); + } else { + ERR_PRINT("Attempted to free invalid ID: " + itos(p_id.get_id())); + } +} +void RenderingDeviceVulkan::free(RID p_id) { + + _THREAD_SAFE_METHOD_ + + _free_dependencies(p_id); //recursively erase dependencies first, to avoid potential API problems + _free_internal(p_id); +} +void RenderingDeviceVulkan::swap_buffers() { + + _THREAD_SAFE_METHOD_ + + { //finalize frame + + if (draw_list) { + ERR_PRINT("Found open draw list at the end of the frame, this should never happen (further drawing will likely not work)."); + } + + if (compute_list) { + ERR_PRINT("Found open compute list at the end of the frame, this should never happen (further compute will likely not work)."); + } + + { //complete the setup buffer (that needs to be processed before anything else) + vkEndCommandBuffer(frames[frame].setup_command_buffer); + vkEndCommandBuffer(frames[frame].draw_command_buffer); + } + screen_prepared = false; + } + + //swap buffers + context->swap_buffers(); + + { //advance frame + + frame = (frame + 1) % frame_count; + + //erase pending resources + _free_pending_resources(frame); + + //create setup command buffer and set as the setup buffer + + { + VkCommandBufferBeginInfo cmdbuf_begin; + cmdbuf_begin.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + cmdbuf_begin.pNext = NULL; + cmdbuf_begin.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + cmdbuf_begin.pInheritanceInfo = NULL; + + VkResult err = vkResetCommandBuffer(frames[frame].setup_command_buffer, 0); + ERR_FAIL_COND(err); + + err = vkBeginCommandBuffer(frames[frame].setup_command_buffer, &cmdbuf_begin); + ERR_FAIL_COND(err); + context->set_setup_buffer(frames[frame].setup_command_buffer); //append now so it's added before everything else + err = vkBeginCommandBuffer(frames[frame].draw_command_buffer, &cmdbuf_begin); + ERR_FAIL_COND(err); + context->append_command_buffer(frames[frame].draw_command_buffer); + } + + //advance current frame + frames_drawn++; + //advance staging buffer if used + if (staging_buffer_used) { + staging_buffer_current = (staging_buffer_current + 1) % staging_buffer_blocks.size(); + staging_buffer_used = false; + } + + if (frames[frame].timestamp_count) { + vkGetQueryPoolResults(device, frames[frame].timestamp_pool, 0, frames[frame].timestamp_count, sizeof(uint64_t) * max_timestamp_query_elements, frames[frame].timestamp_result_values, sizeof(uint64_t), VK_QUERY_RESULT_64_BIT); + SWAP(frames[frame].timestamp_names, frames[frame].timestamp_result_names); + SWAP(frames[frame].timestamp_cpu_values, frames[frame].timestamp_cpu_result_values); + } + + frames[frame].timestamp_result_count = frames[frame].timestamp_count; + frames[frame].timestamp_count = 0; + frames[frame].index = Engine::get_singleton()->get_frames_drawn(); + } +} + +void RenderingDeviceVulkan::_free_pending_resources(int p_frame) { + //free in dependency usage order, so nothing weird happens + //pipelines + while (frames[p_frame].render_pipelines_to_dispose_of.front()) { + RenderPipeline *pipeline = &frames[p_frame].render_pipelines_to_dispose_of.front()->get(); + + vkDestroyPipeline(device, pipeline->pipeline, NULL); + + frames[p_frame].render_pipelines_to_dispose_of.pop_front(); + } + + while (frames[p_frame].compute_pipelines_to_dispose_of.front()) { + ComputePipeline *pipeline = &frames[p_frame].compute_pipelines_to_dispose_of.front()->get(); + + vkDestroyPipeline(device, pipeline->pipeline, NULL); + + frames[p_frame].compute_pipelines_to_dispose_of.pop_front(); + } + + //uniform sets + while (frames[p_frame].uniform_sets_to_dispose_of.front()) { + UniformSet *uniform_set = &frames[p_frame].uniform_sets_to_dispose_of.front()->get(); + + vkFreeDescriptorSets(device, uniform_set->pool->pool, 1, &uniform_set->descriptor_set); + _descriptor_pool_free(uniform_set->pool_key, uniform_set->pool); + + frames[p_frame].uniform_sets_to_dispose_of.pop_front(); + } + + //buffer views + while (frames[p_frame].buffer_views_to_dispose_of.front()) { + VkBufferView buffer_view = frames[p_frame].buffer_views_to_dispose_of.front()->get(); + + vkDestroyBufferView(device, buffer_view, NULL); + + frames[p_frame].buffer_views_to_dispose_of.pop_front(); + } + + //shaders + while (frames[p_frame].shaders_to_dispose_of.front()) { + Shader *shader = &frames[p_frame].shaders_to_dispose_of.front()->get(); + + //descriptor set layout for each set + for (int i = 0; i < shader->sets.size(); i++) { + vkDestroyDescriptorSetLayout(device, shader->sets[i].descriptor_set_layout, NULL); + } + + //pipeline layout + vkDestroyPipelineLayout(device, shader->pipeline_layout, NULL); + + //shaders themselves + for (int i = 0; i < shader->pipeline_stages.size(); i++) { + vkDestroyShaderModule(device, shader->pipeline_stages[i].module, NULL); + } + + frames[p_frame].shaders_to_dispose_of.pop_front(); + } + + //samplers + while (frames[p_frame].samplers_to_dispose_of.front()) { + VkSampler sampler = frames[p_frame].samplers_to_dispose_of.front()->get(); + + vkDestroySampler(device, sampler, NULL); + + frames[p_frame].samplers_to_dispose_of.pop_front(); + } + + //framebuffers + while (frames[p_frame].framebuffers_to_dispose_of.front()) { + Framebuffer *framebuffer = &frames[p_frame].framebuffers_to_dispose_of.front()->get(); + + for (Map<Framebuffer::VersionKey, Framebuffer::Version>::Element *E = framebuffer->framebuffers.front(); E; E = E->next()) { + //first framebuffer, then render pass because it depends on it + vkDestroyFramebuffer(device, E->get().framebuffer, NULL); + vkDestroyRenderPass(device, E->get().render_pass, NULL); + } + + frames[p_frame].framebuffers_to_dispose_of.pop_front(); + } + + //textures + while (frames[p_frame].textures_to_dispose_of.front()) { + Texture *texture = &frames[p_frame].textures_to_dispose_of.front()->get(); + + if (texture->bound) { + WARN_PRINT("Deleted a texture while it was bound.."); + } + vkDestroyImageView(device, texture->view, NULL); + if (texture->owner.is_null()) { + //actually owns the image and the allocation too + vmaDestroyImage(allocator, texture->image, texture->allocation); + } + frames[p_frame].textures_to_dispose_of.pop_front(); + } + + //buffers + while (frames[p_frame].buffers_to_dispose_of.front()) { + + _buffer_free(&frames[p_frame].buffers_to_dispose_of.front()->get()); + + frames[p_frame].buffers_to_dispose_of.pop_front(); + } +} + +void RenderingDeviceVulkan::prepare_screen_for_drawing() { + _THREAD_SAFE_METHOD_ + context->prepare_buffers(); + screen_prepared = true; +} + +uint32_t RenderingDeviceVulkan::get_frame_delay() const { + return frame_count; +} + +void RenderingDeviceVulkan::_flush(bool p_current_frame) { + + //not doing this crashes RADV (undefined behavior) + if (p_current_frame) { + vkEndCommandBuffer(frames[frame].setup_command_buffer); + vkEndCommandBuffer(frames[frame].draw_command_buffer); + } + context->flush(p_current_frame, p_current_frame); + //re-create the setup command + if (p_current_frame) { + VkCommandBufferBeginInfo cmdbuf_begin; + cmdbuf_begin.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + cmdbuf_begin.pNext = NULL; + cmdbuf_begin.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + cmdbuf_begin.pInheritanceInfo = NULL; + + VkResult err = vkBeginCommandBuffer(frames[frame].setup_command_buffer, &cmdbuf_begin); + ERR_FAIL_COND(err); + context->set_setup_buffer(frames[frame].setup_command_buffer); //append now so it's added before everything else + } + + if (p_current_frame) { + VkCommandBufferBeginInfo cmdbuf_begin; + cmdbuf_begin.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + cmdbuf_begin.pNext = NULL; + cmdbuf_begin.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + cmdbuf_begin.pInheritanceInfo = NULL; + + VkResult err = vkBeginCommandBuffer(frames[frame].draw_command_buffer, &cmdbuf_begin); + ERR_FAIL_COND(err); + context->append_command_buffer(frames[frame].draw_command_buffer); + } +} + +void RenderingDeviceVulkan::initialize(VulkanContext *p_context) { + + context = p_context; + device = p_context->get_device(); + frame_count = p_context->get_swapchain_image_count() + 1; //always need one extra to ensure it's unused at any time, without having to use a fence for this. + limits = p_context->get_device_limits(); + max_timestamp_query_elements = 256; + + { //initialize allocator + + VmaAllocatorCreateInfo allocatorInfo; + memset(&allocatorInfo, 0, sizeof(VmaAllocatorCreateInfo)); + allocatorInfo.physicalDevice = p_context->get_physical_device(); + allocatorInfo.device = device; + vmaCreateAllocator(&allocatorInfo, &allocator); + } + + frames = memnew_arr(Frame, frame_count); + frame = 0; + //create setup and frame buffers + for (int i = 0; i < frame_count; i++) { + + frames[i].index = 0; + + { //create command pool, one per frame is recommended + VkCommandPoolCreateInfo cmd_pool_info; + cmd_pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; + cmd_pool_info.pNext = NULL; + cmd_pool_info.queueFamilyIndex = p_context->get_graphics_queue(); + cmd_pool_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; + + VkResult res = vkCreateCommandPool(device, &cmd_pool_info, NULL, &frames[i].command_pool); + ERR_FAIL_COND(res); + } + + { //create command buffers + + VkCommandBufferAllocateInfo cmdbuf; + //no command buffer exists, create it. + cmdbuf.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + cmdbuf.pNext = NULL; + cmdbuf.commandPool = frames[i].command_pool; + cmdbuf.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + cmdbuf.commandBufferCount = 1; + + VkResult err = vkAllocateCommandBuffers(device, &cmdbuf, &frames[i].setup_command_buffer); + ERR_CONTINUE(err); + + err = vkAllocateCommandBuffers(device, &cmdbuf, &frames[i].draw_command_buffer); + ERR_CONTINUE(err); + } + + { + //create query pool + VkQueryPoolCreateInfo query_pool_create_info; + query_pool_create_info.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO; + query_pool_create_info.flags = 0; + query_pool_create_info.pNext = NULL; + query_pool_create_info.queryType = VK_QUERY_TYPE_TIMESTAMP; + query_pool_create_info.queryCount = max_timestamp_query_elements; + query_pool_create_info.pipelineStatistics = 0; + + vkCreateQueryPool(device, &query_pool_create_info, NULL, &frames[i].timestamp_pool); + + frames[i].timestamp_names = memnew_arr(String, max_timestamp_query_elements); + frames[i].timestamp_cpu_values = memnew_arr(uint64_t, max_timestamp_query_elements); + frames[i].timestamp_count = 0; + frames[i].timestamp_result_names = memnew_arr(String, max_timestamp_query_elements); + frames[i].timestamp_cpu_result_values = memnew_arr(uint64_t, max_timestamp_query_elements); + frames[i].timestamp_result_values = memnew_arr(uint64_t, max_timestamp_query_elements); + frames[i].timestamp_result_count = 0; + } + } + + { + //begin the first command buffer for the first frame, so + //setting up things can be done in the meantime until swap_buffers(), which is called before advance. + VkCommandBufferBeginInfo cmdbuf_begin; + cmdbuf_begin.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + cmdbuf_begin.pNext = NULL; + cmdbuf_begin.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + cmdbuf_begin.pInheritanceInfo = NULL; + + VkResult err = vkBeginCommandBuffer(frames[0].setup_command_buffer, &cmdbuf_begin); + ERR_FAIL_COND(err); + context->set_setup_buffer(frames[0].setup_command_buffer); //append now so it's added before everything else + + err = vkBeginCommandBuffer(frames[0].draw_command_buffer, &cmdbuf_begin); + ERR_FAIL_COND(err); + context->append_command_buffer(frames[0].draw_command_buffer); + } + + staging_buffer_block_size = GLOBAL_DEF("rendering/vulkan/staging_buffer/block_size_kb", 256); + staging_buffer_block_size = MAX(4, staging_buffer_block_size); + staging_buffer_block_size *= 1024; //kb -> bytes + staging_buffer_max_size = GLOBAL_DEF("rendering/vulkan/staging_buffer/max_size_mb", 128); + staging_buffer_max_size = MAX(1, staging_buffer_max_size); + staging_buffer_max_size *= 1024 * 1024; + + if (staging_buffer_max_size < staging_buffer_block_size * 4) { + //validate enough blocks + staging_buffer_max_size = staging_buffer_block_size * 4; + } + texture_upload_region_size_px = GLOBAL_DEF("rendering/vulkan/staging_buffer/texture_upload_region_size_px", 64); + texture_upload_region_size_px = nearest_power_of_2_templated(texture_upload_region_size_px); + + frames_drawn = frame_count; //start from frame count, so everything else is immediately old + + //ensure current staging block is valid and at least one per frame exists + staging_buffer_current = 0; + staging_buffer_used = false; + + for (int i = 0; i < frame_count; i++) { + //staging was never used, create a block + Error err = _insert_staging_block(); + ERR_CONTINUE(err != OK); + } + + max_descriptors_per_pool = GLOBAL_DEF("rendering/vulkan/descriptor_pools/max_descriptors_per_pool", 64); + + //check to make sure DescriptorPoolKey is good + ERR_FAIL_COND(sizeof(uint64_t) * 3 < UNIFORM_TYPE_MAX * sizeof(uint16_t)); + + draw_list = NULL; + draw_list_count = 0; + draw_list_split = false; + + compute_list = NULL; +} + +template <class T> +void RenderingDeviceVulkan::_free_rids(T &p_owner, const char *p_type) { + List<RID> owned; + p_owner.get_owned_list(&owned); + if (owned.size()) { + WARN_PRINT(itos(owned.size()) + " RIDs of type '" + p_type + "' were leaked."); + for (List<RID>::Element *E = owned.front(); E; E = E->next()) { + free(E->get()); + } + } +} + +void RenderingDeviceVulkan::capture_timestamp(const String &p_name, bool p_sync_to_draw) { + + ERR_FAIL_COND(frames[frame].timestamp_count >= max_timestamp_query_elements); + + { + VkMemoryBarrier memoryBarrier; + + memoryBarrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER; + memoryBarrier.pNext = NULL; + memoryBarrier.srcAccessMask = VK_ACCESS_INDIRECT_COMMAND_READ_BIT | + VK_ACCESS_INDEX_READ_BIT | + VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT | + VK_ACCESS_UNIFORM_READ_BIT | + VK_ACCESS_INPUT_ATTACHMENT_READ_BIT | + VK_ACCESS_SHADER_READ_BIT | + VK_ACCESS_SHADER_WRITE_BIT | + VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | + VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | + VK_ACCESS_TRANSFER_READ_BIT | + VK_ACCESS_TRANSFER_WRITE_BIT | + VK_ACCESS_HOST_READ_BIT | + VK_ACCESS_HOST_WRITE_BIT; + memoryBarrier.dstAccessMask = VK_ACCESS_INDIRECT_COMMAND_READ_BIT | + VK_ACCESS_INDEX_READ_BIT | + VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT | + VK_ACCESS_UNIFORM_READ_BIT | + VK_ACCESS_INPUT_ATTACHMENT_READ_BIT | + VK_ACCESS_SHADER_READ_BIT | + VK_ACCESS_SHADER_WRITE_BIT | + VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | + VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | + VK_ACCESS_TRANSFER_READ_BIT | + VK_ACCESS_TRANSFER_WRITE_BIT | + VK_ACCESS_HOST_READ_BIT | + VK_ACCESS_HOST_WRITE_BIT; + + vkCmdPipelineBarrier(p_sync_to_draw ? frames[frame].draw_command_buffer : frames[frame].setup_command_buffer, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 1, &memoryBarrier, 0, NULL, 0, NULL); + } + vkCmdWriteTimestamp(p_sync_to_draw ? frames[frame].draw_command_buffer : frames[frame].setup_command_buffer, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, frames[frame].timestamp_pool, frames[frame].timestamp_count); + frames[frame].timestamp_names[frames[frame].timestamp_count] = p_name; + frames[frame].timestamp_cpu_values[frames[frame].timestamp_count] = OS::get_singleton()->get_ticks_usec(); + frames[frame].timestamp_count++; +} + +uint32_t RenderingDeviceVulkan::get_captured_timestamps_count() const { + return frames[frame].timestamp_result_count; +} + +uint64_t RenderingDeviceVulkan::get_captured_timestamps_frame() const { + return frames[frame].index; +} + +uint64_t RenderingDeviceVulkan::get_captured_timestamp_gpu_time(uint32_t p_index) const { + ERR_FAIL_UNSIGNED_INDEX_V(p_index, frames[frame].timestamp_result_count, 0); + return frames[frame].timestamp_result_values[p_index] * limits.timestampPeriod; +} +uint64_t RenderingDeviceVulkan::get_captured_timestamp_cpu_time(uint32_t p_index) const { + ERR_FAIL_UNSIGNED_INDEX_V(p_index, frames[frame].timestamp_result_count, 0); + return frames[frame].timestamp_cpu_result_values[p_index]; +} +String RenderingDeviceVulkan::get_captured_timestamp_name(uint32_t p_index) const { + ERR_FAIL_UNSIGNED_INDEX_V(p_index, frames[frame].timestamp_result_count, String()); + return frames[frame].timestamp_result_names[p_index]; +} + +int RenderingDeviceVulkan::limit_get(Limit p_limit) { + switch (p_limit) { + case LIMIT_MAX_BOUND_UNIFORM_SETS: return limits.maxBoundDescriptorSets; + case LIMIT_MAX_FRAMEBUFFER_COLOR_ATTACHMENTS: return limits.maxColorAttachments; + case LIMIT_MAX_TEXTURES_PER_UNIFORM_SET: return limits.maxDescriptorSetSampledImages; + case LIMIT_MAX_SAMPLERS_PER_UNIFORM_SET: return limits.maxDescriptorSetSamplers; + case LIMIT_MAX_STORAGE_BUFFERS_PER_UNIFORM_SET: return limits.maxDescriptorSetStorageBuffers; + case LIMIT_MAX_STORAGE_IMAGES_PER_UNIFORM_SET: return limits.maxDescriptorSetStorageImages; + case LIMIT_MAX_UNIFORM_BUFFERS_PER_UNIFORM_SET: return limits.maxDescriptorSetUniformBuffers; + case LIMIT_MAX_DRAW_INDEXED_INDEX: return limits.maxDrawIndexedIndexValue; + case LIMIT_MAX_FRAMEBUFFER_HEIGHT: return limits.maxFramebufferHeight; + case LIMIT_MAX_FRAMEBUFFER_WIDTH: return limits.maxFramebufferWidth; + case LIMIT_MAX_TEXTURE_ARRAY_LAYERS: return limits.maxImageArrayLayers; + case LIMIT_MAX_TEXTURE_SIZE_1D: return limits.maxImageDimension1D; + case LIMIT_MAX_TEXTURE_SIZE_2D: return limits.maxImageDimension2D; + case LIMIT_MAX_TEXTURE_SIZE_3D: return limits.maxImageDimension3D; + case LIMIT_MAX_TEXTURE_SIZE_CUBE: return limits.maxImageDimensionCube; + case LIMIT_MAX_TEXTURES_PER_SHADER_STAGE: return limits.maxPerStageDescriptorSampledImages; + case LIMIT_MAX_SAMPLERS_PER_SHADER_STAGE: return limits.maxPerStageDescriptorSamplers; + case LIMIT_MAX_STORAGE_BUFFERS_PER_SHADER_STAGE: return limits.maxPerStageDescriptorStorageBuffers; + case LIMIT_MAX_STORAGE_IMAGES_PER_SHADER_STAGE: return limits.maxPerStageDescriptorStorageImages; + case LIMIT_MAX_UNIFORM_BUFFERS_PER_SHADER_STAGE: return limits.maxPerStageDescriptorUniformBuffers; + case LIMIT_MAX_PUSH_CONSTANT_SIZE: return limits.maxPushConstantsSize; + case LIMIT_MAX_UNIFORM_BUFFER_SIZE: return limits.maxUniformBufferRange; + case LIMIT_MAX_VERTEX_INPUT_ATTRIBUTE_OFFSET: return limits.maxVertexInputAttributeOffset; + case LIMIT_MAX_VERTEX_INPUT_ATTRIBUTES: return limits.maxVertexInputAttributes; + case LIMIT_MAX_VERTEX_INPUT_BINDINGS: return limits.maxVertexInputBindings; + case LIMIT_MAX_VERTEX_INPUT_BINDING_STRIDE: return limits.maxVertexInputBindingStride; + case LIMIT_MIN_UNIFORM_BUFFER_OFFSET_ALIGNMENT: return limits.minUniformBufferOffsetAlignment; + case LIMIT_MAX_COMPUTE_WORKGROUP_COUNT_X: return limits.maxComputeWorkGroupCount[0]; + case LIMIT_MAX_COMPUTE_WORKGROUP_COUNT_Y: return limits.maxComputeWorkGroupCount[1]; + case LIMIT_MAX_COMPUTE_WORKGROUP_COUNT_Z: return limits.maxComputeWorkGroupCount[2]; + case LIMIT_MAX_COMPUTE_WORKGROUP_INVOCATIONS: return limits.maxComputeWorkGroupInvocations; + case LIMIT_MAX_COMPUTE_WORKGROUP_SIZE_X: return limits.maxComputeWorkGroupSize[0]; + case LIMIT_MAX_COMPUTE_WORKGROUP_SIZE_Y: return limits.maxComputeWorkGroupSize[1]; + case LIMIT_MAX_COMPUTE_WORKGROUP_SIZE_Z: return limits.maxComputeWorkGroupSize[2]; + + default: ERR_FAIL_V(0); + } + + return 0; +} + +void RenderingDeviceVulkan::finalize() { + + //free all resources + + _flush(false); + + _free_rids(render_pipeline_owner, "Pipeline"); + _free_rids(compute_pipeline_owner, "Compute"); + _free_rids(uniform_set_owner, "UniformSet"); + _free_rids(texture_buffer_owner, "TextureBuffer"); + _free_rids(storage_buffer_owner, "StorageBuffer"); + _free_rids(uniform_buffer_owner, "UniformBuffer"); + _free_rids(shader_owner, "Shader"); + _free_rids(index_array_owner, "IndexArray"); + _free_rids(index_buffer_owner, "IndexBuffer"); + _free_rids(vertex_array_owner, "VertexArray"); + _free_rids(vertex_buffer_owner, "VertexBuffer"); + _free_rids(framebuffer_owner, "Framebuffer"); + _free_rids(sampler_owner, "Sampler"); + { + //for textures it's a bit more difficult because they may be shared + List<RID> owned; + texture_owner.get_owned_list(&owned); + if (owned.size()) { + WARN_PRINT(itos(owned.size()) + " RIDs of type 'Texture' were leaked."); + //free shared first + for (List<RID>::Element *E = owned.front(); E;) { + + List<RID>::Element *N = E->next(); + if (texture_is_shared(E->get())) { + free(E->get()); + owned.erase(E->get()); + } + E = N; + } + //free non shared second, this will avoid an error trying to free unexisting textures due to dependencies. + for (List<RID>::Element *E = owned.front(); E; E = E->next()) { + free(E->get()); + } + } + } + + //free everything pending + for (int i = 0; i < frame_count; i++) { + int f = (frame + i) % frame_count; + _free_pending_resources(f); + vkDestroyCommandPool(device, frames[i].command_pool, NULL); + vkDestroyQueryPool(device, frames[i].timestamp_pool, NULL); + memdelete_arr(frames[i].timestamp_names); + memdelete_arr(frames[i].timestamp_cpu_values); + memdelete_arr(frames[i].timestamp_result_names); + memdelete_arr(frames[i].timestamp_result_values); + memdelete_arr(frames[i].timestamp_cpu_result_values); + } + + for (int i = 0; i < split_draw_list_allocators.size(); i++) { + vkDestroyCommandPool(device, split_draw_list_allocators[i].command_pool, NULL); + } + + memdelete_arr(frames); + + for (int i = 0; i < staging_buffer_blocks.size(); i++) { + vmaDestroyBuffer(allocator, staging_buffer_blocks[i].buffer, staging_buffer_blocks[i].allocation); + } + + //all these should be clear at this point + ERR_FAIL_COND(descriptor_pools.size()); + ERR_FAIL_COND(dependency_map.size()); + ERR_FAIL_COND(reverse_dependency_map.size()); +} + +RenderingDeviceVulkan::RenderingDeviceVulkan() { + screen_prepared = false; +} diff --git a/drivers/vulkan/rendering_device_vulkan.h b/drivers/vulkan/rendering_device_vulkan.h new file mode 100644 index 0000000000..8ef24d319b --- /dev/null +++ b/drivers/vulkan/rendering_device_vulkan.h @@ -0,0 +1,1127 @@ +/*************************************************************************/ +/* rendering_device_vulkan.h */ +/*************************************************************************/ +/* 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. */ +/*************************************************************************/ + +#ifndef RENDERING_DEVICE_VULKAN_H +#define RENDERING_DEVICE_VULKAN_H + +#include "core/oa_hash_map.h" +#include "core/os/thread_safe.h" +#include "core/rid_owner.h" +#include "servers/visual/rendering_device.h" + +#ifdef DEBUG_ENABLED +#define _DEBUG +#endif +#include "vk_mem_alloc.h" +#include <vulkan/vulkan.h> +//todo: +//compute +//push constants +//views of texture slices + +class VulkanContext; + +class RenderingDeviceVulkan : public RenderingDevice { + + _THREAD_SAFE_CLASS_ + + // Miscellaneous tables that map + // our enums to enums used + // by vulkan. + + VkPhysicalDeviceLimits limits; + static const VkFormat vulkan_formats[DATA_FORMAT_MAX]; + static const char *named_formats[DATA_FORMAT_MAX]; + static const VkCompareOp compare_operators[COMPARE_OP_MAX]; + static const VkStencilOp stencil_operations[STENCIL_OP_MAX]; + static const VkSampleCountFlagBits rasterization_sample_count[TEXTURE_SAMPLES_MAX]; + static const VkLogicOp logic_operations[RenderingDevice::LOGIC_OP_MAX]; + static const VkBlendFactor blend_factors[RenderingDevice::BLEND_FACTOR_MAX]; + static const VkBlendOp blend_operations[RenderingDevice::BLEND_OP_MAX]; + static const VkSamplerAddressMode address_modes[SAMPLER_REPEAT_MODE_MAX]; + static const VkBorderColor sampler_border_colors[SAMPLER_BORDER_COLOR_MAX]; + static const VkImageType vulkan_image_type[TEXTURE_TYPE_MAX]; + + // Functions used for format + // validation, and ensures the + // user passes valid data. + + static int get_format_vertex_size(DataFormat p_format); + static uint32_t get_image_format_pixel_size(DataFormat p_format); + static void get_compressed_image_format_block_dimensions(DataFormat p_format, uint32_t &r_w, uint32_t &r_h); + uint32_t get_compressed_image_format_block_byte_size(DataFormat p_format); + static uint32_t get_compressed_image_format_pixel_rshift(DataFormat p_format); + static uint32_t get_image_format_required_size(DataFormat p_format, uint32_t p_width, uint32_t p_height, uint32_t p_depth, uint32_t p_mipmaps, uint32_t *r_blockw = NULL, uint32_t *r_blockh = NULL, uint32_t *r_depth = NULL); + static uint32_t get_image_required_mipmaps(uint32_t p_width, uint32_t p_height, uint32_t p_depth); + static bool format_has_stencil(DataFormat p_format); + + /***************************/ + /**** ID INFRASTRUCTURE ****/ + /***************************/ + + enum IDType { + ID_TYPE_FRAMEBUFFER_FORMAT, + ID_TYPE_VERTEX_FORMAT, + ID_TYPE_DRAW_LIST, + ID_TYPE_SPLIT_DRAW_LIST, + ID_TYPE_COMPUTE_LIST, + ID_TYPE_MAX, + ID_BASE_SHIFT = 58 //5 bits for ID types + }; + + VkDevice device; + + Map<RID, Set<RID> > dependency_map; //IDs to IDs that depend on it + Map<RID, Set<RID> > reverse_dependency_map; //same as above, but in reverse + + void _add_dependency(RID p_id, RID p_depends_on); + void _free_dependencies(RID p_id); + + /*****************/ + /**** TEXTURE ****/ + /*****************/ + + // In Vulkan, the concept of textures does not exist, + // intead there is the image (the memory prety much, + // the view (how the memory is interpreted) and the + // sampler (how it's sampled from the shader). + // + // Texture here includes the first two stages, but + // It's possible to create textures sharing the image + // but with different views. The main use case for this + // is textures that can be read as both SRGB/Linear, + // or slices of a texture (a mipmap, a layer, a 3D slice) + // for a framebuffer to render into it. + + struct Texture { + + VkImage image; + VmaAllocation allocation; + VmaAllocationInfo allocation_info; + VkImageView view; + + TextureType type; + DataFormat format; + TextureSamples samples; + uint32_t width; + uint32_t height; + uint32_t depth; + uint32_t layers; + uint32_t mipmaps; + uint32_t usage_flags; + + Vector<DataFormat> allowed_shared_formats; + + VkImageLayout layout; + + uint32_t read_aspect_mask; + uint32_t barrier_aspect_mask; + bool bound; //bound to framebffer + RID owner; + }; + + RID_Owner<Texture, true> texture_owner; + uint32_t texture_upload_region_size_px; + + PoolVector<uint8_t> _texture_get_data_from_image(Texture *tex, VkImage p_image, VmaAllocation p_allocation, uint32_t p_layer, bool p_2d = false); + + /*****************/ + /**** SAMPLER ****/ + /*****************/ + + RID_Owner<VkSampler> sampler_owner; + + /***************************/ + /**** BUFFER MANAGEMENT ****/ + /***************************/ + + // These are temporary buffers on CPU memory that hold + // the information until the CPU fetches it and places it + // either on GPU buffers, or images (textures). It ensures + // updates are properly synchronized with whathever the + // GPU is doing. + // + // The logic here is as follows, only 3 of these + // blocks are created at the beginning (one per frame) + // they can each belong to a frame (assigned to current when + // used) and they can only be reused after the same frame is + // recycled. + // + // When CPU requires to allocate more than what is available, + // more of these buffers are created. If a limit is reached, + // then a fence will ensure will wait for blocks allocated + // in previous frames are processed. If that fails, then + // another fence will ensure everything pending for the current + // frame is processed (effectively stalling). + // + // See the comments in the code to understand better how it works. + + struct StagingBufferBlock { + VkBuffer buffer; + VmaAllocation allocation; + uint64_t frame_used; + uint32_t fill_amount; + }; + + Vector<StagingBufferBlock> staging_buffer_blocks; + int staging_buffer_current; + uint32_t staging_buffer_block_size; + uint64_t staging_buffer_max_size; + bool staging_buffer_used; + + Error _staging_buffer_allocate(uint32_t p_amount, uint32_t p_required_align, uint32_t &r_alloc_offset, uint32_t &r_alloc_size, bool p_can_segment = true, bool p_on_draw_command_buffer = false); + Error _insert_staging_block(); + + struct Buffer { + + uint32_t size; + VkBuffer buffer; + VmaAllocation allocation; + VkDescriptorBufferInfo buffer_info; //used for binding + Buffer() { + size = 0; + buffer = NULL; + allocation = NULL; + } + }; + + Error _buffer_allocate(Buffer *p_buffer, uint32_t p_size, uint32_t p_usage, VmaMemoryUsage p_mapping); + Error _buffer_free(Buffer *p_buffer); + Error _buffer_update(Buffer *p_buffer, size_t p_offset, const uint8_t *p_data, size_t p_data_size, bool p_use_draw_command_buffer = false, uint32_t p_required_align = 32); + + void _full_barrier(bool p_sync_with_draw); + void _memory_barrier(VkPipelineStageFlags p_src_stage_mask, VkPipelineStageFlags p_dst_stage_mask, VkAccessFlags p_src_access, VkAccessFlags p_dst_sccess, bool p_sync_with_draw); + void _buffer_memory_barrier(VkBuffer buffer, uint64_t p_from, uint64_t p_size, VkPipelineStageFlags p_src_stage_mask, VkPipelineStageFlags p_dst_stage_mask, VkAccessFlags p_src_access, VkAccessFlags p_dst_sccess, bool p_sync_with_draw); + + /*********************/ + /**** FRAMEBUFFER ****/ + /*********************/ + + // In Vulkan, framebuffers work similar to how they + // do in OpenGL, with the exception that + // the "format" (vkRenderPass) is not dynamic + // and must be more or less the same as the one + // used for the render pipelines. + + struct FramebufferFormatKey { + Vector<AttachmentFormat> attachments; + bool operator<(const FramebufferFormatKey &p_key) const { + + int as = attachments.size(); + int bs = p_key.attachments.size(); + if (as != bs) { + return as < bs; + } + + const AttachmentFormat *af_a = attachments.ptr(); + const AttachmentFormat *af_b = p_key.attachments.ptr(); + for (int i = 0; i < as; i++) { + const AttachmentFormat &a = af_a[i]; + const AttachmentFormat &b = af_b[i]; + if (a.format != b.format) { + return a.format < b.format; + } + if (a.samples != b.samples) { + return a.samples < b.samples; + } + if (a.usage_flags != b.usage_flags) { + return a.usage_flags < b.usage_flags; + } + } + + return false; //equal + } + }; + + VkRenderPass _render_pass_create(const Vector<AttachmentFormat> &p_format, InitialAction p_initial_action, FinalAction p_final_action, InitialAction p_initial_depth_action, FinalAction p_final_depthcolor_action, int *r_color_attachment_count = NULL); + + // This is a cache and it's never freed, it ensures + // IDs for a given format are always unique. + Map<FramebufferFormatKey, FramebufferFormatID> framebuffer_format_cache; + struct FramebufferFormat { + const Map<FramebufferFormatKey, FramebufferFormatID>::Element *E; + VkRenderPass render_pass; //here for constructing shaders, never used, see section (7.2. Render Pass Compatibility from Vulkan spec) + int color_attachments; //used for pipeline validation + TextureSamples samples; + }; + + Map<FramebufferFormatID, FramebufferFormat> framebuffer_formats; + + struct Framebuffer { + FramebufferFormatID format_id; + struct VersionKey { + InitialAction initial_color_action; + FinalAction final_color_action; + InitialAction initial_depth_action; + FinalAction final_depth_action; + bool operator<(const VersionKey &p_key) const { + if (initial_color_action == p_key.initial_color_action) { + if (final_color_action == p_key.final_color_action) { + if (initial_depth_action == p_key.initial_depth_action) { + return final_depth_action < p_key.final_depth_action; + } else { + return initial_depth_action < p_key.initial_depth_action; + } + } else { + return final_color_action < p_key.final_color_action; + } + } else { + return initial_color_action < p_key.initial_color_action; + } + } + }; + + uint32_t storage_mask; + Vector<RID> texture_ids; + + struct Version { + VkFramebuffer framebuffer; + VkRenderPass render_pass; //this one is owned + }; + + Map<VersionKey, Version> framebuffers; + Size2 size; + }; + + RID_Owner<Framebuffer, true> framebuffer_owner; + + /***********************/ + /**** VERTEX BUFFER ****/ + /***********************/ + + // Vertex buffers in Vulkan are similar to how + // they work in OpenGL, except that instead of + // an attribtue index, there is a buffer binding + // index (for binding the buffers in real-time) + // and a location index (what is used in the shader). + // + // This mapping is done here internally, and it's not + // exposed. + + RID_Owner<Buffer, true> vertex_buffer_owner; + + struct VertexDescriptionKey { + Vector<VertexDescription> vertex_formats; + bool operator==(const VertexDescriptionKey &p_key) const { + int vdc = vertex_formats.size(); + int vdck = p_key.vertex_formats.size(); + + if (vdc != vdck) { + return false; + } else { + const VertexDescription *a_ptr = vertex_formats.ptr(); + const VertexDescription *b_ptr = p_key.vertex_formats.ptr(); + for (int i = 0; i < vdc; i++) { + const VertexDescription &a = a_ptr[i]; + const VertexDescription &b = b_ptr[i]; + + if (a.location != b.location) { + return false; + } + if (a.offset != b.offset) { + return false; + } + if (a.format != b.format) { + return false; + } + if (a.stride != b.stride) { + return false; + } + return a.frequency != b.frequency; + } + return true; //they are equal + } + } + + uint32_t hash() const { + int vdc = vertex_formats.size(); + uint32_t h = hash_djb2_one_32(vdc); + const VertexDescription *ptr = vertex_formats.ptr(); + for (int i = 0; i < vdc; i++) { + const VertexDescription &vd = ptr[i]; + h = hash_djb2_one_32(vd.location, h); + h = hash_djb2_one_32(vd.offset, h); + h = hash_djb2_one_32(vd.format, h); + h = hash_djb2_one_32(vd.stride, h); + h = hash_djb2_one_32(vd.frequency, h); + } + return h; + } + }; + + struct VertexDescriptionHash { + static _FORCE_INLINE_ uint32_t hash(const VertexDescriptionKey &p_key) { + return p_key.hash(); + } + }; + + // This is a cache and it's never freed, it ensures that + // ID used for a specific format always remain the same. + HashMap<VertexDescriptionKey, VertexFormatID, VertexDescriptionHash> vertex_format_cache; + + struct VertexDescriptionCache { + Vector<VertexDescription> vertex_formats; + VkVertexInputBindingDescription *bindings; + VkVertexInputAttributeDescription *attributes; + VkPipelineVertexInputStateCreateInfo create_info; + }; + + Map<VertexFormatID, VertexDescriptionCache> vertex_formats; + + struct VertexArray { + RID buffer; + VertexFormatID description; + int vertex_count; + uint32_t max_instances_allowed; + + Vector<VkBuffer> buffers; //not owned, just referenced + Vector<VkDeviceSize> offsets; + }; + + RID_Owner<VertexArray, true> vertex_array_owner; + + struct IndexBuffer : public Buffer { + uint32_t max_index; //used for validation + uint32_t index_count; + VkIndexType index_type; + bool supports_restart_indices; + }; + + RID_Owner<IndexBuffer, true> index_buffer_owner; + + struct IndexArray { + uint32_t max_index; //remember the maximum index here too, for validation + VkBuffer buffer; //not owned, inherited from index buffer + uint32_t offset; + uint32_t indices; + VkIndexType index_type; + bool supports_restart_indices; + }; + + RID_Owner<IndexArray, true> index_array_owner; + + /****************/ + /**** SHADER ****/ + /****************/ + + // Vulkan specifies a really complex behavior for the application + // in order to tell when descriptor sets need to be re-bound (or not). + // "When binding a descriptor set (see Descriptor Set Binding) to set + // number N, if the previously bound descriptor sets for sets zero + // through N-1 were all bound using compatible pipeline layouts, + // then performing this binding does not disturb any of the lower numbered sets. + // If, additionally, the previous bound descriptor set for set N was + // bound using a pipeline layout compatible for set N, then the bindings + // in sets numbered greater than N are also not disturbed." + // As a result, we need to figure out quickly when something is no longer "compatible". + // in order to avoid costly rebinds. + + enum { + MAX_UNIFORM_SETS = 16 + }; + + struct UniformInfo { + UniformType type; + int binding; + uint32_t stages; + int length; //size of arrays (in total elements), or ubos (in bytes * total elements) + + bool operator!=(const UniformInfo &p_info) const { + return (binding != p_info.binding || type != p_info.type || stages != p_info.stages || length != p_info.length); + } + + bool operator<(const UniformInfo &p_info) const { + if (binding != p_info.binding) { + return binding < p_info.binding; + } + if (type != p_info.type) { + return type < p_info.type; + } + if (stages != p_info.stages) { + return stages < p_info.stages; + } + return length < p_info.length; + } + }; + + struct UniformSetFormat { + Vector<UniformInfo> uniform_info; + bool operator<(const UniformSetFormat &p_format) const { + uint32_t size = uniform_info.size(); + uint32_t psize = p_format.uniform_info.size(); + + if (size != psize) { + return size < psize; + } + + const UniformInfo *infoptr = uniform_info.ptr(); + const UniformInfo *pinfoptr = p_format.uniform_info.ptr(); + + for (uint32_t i = 0; i < size; i++) { + if (infoptr[i] != pinfoptr[i]) { + return infoptr[i] < pinfoptr[i]; + } + } + + return false; + } + }; + + // Always grows, never shrinks, ensuring unique IDs, but we assume + // the amount of formats will never be a problem, as the amount of shaders + // in a game is limited. + Map<UniformSetFormat, uint32_t> uniform_set_format_cache; + + // Shaders in Vulkan are just pretty much + // precompiled blocks of SPIR-V bytecode. They + // are most likely not really compiled to host + // assembly until a pipeline is created. + // + // When supplying the shaders, this implementation + // will use the reflection abilities of glslang to + // understand and cache everything required to + // create and use the descriptor sets (Vulkan's + // biggest pain). + // + // Additionally, hashes are created for every set + // to do quick validation and ensuring the user + // does not submit something invalid. + + struct Shader { + + struct Set { + + Vector<UniformInfo> uniform_info; + VkDescriptorSetLayout descriptor_set_layout; + }; + + uint32_t vertex_input_mask; //inputs used, this is mostly for validation + int fragment_outputs; + + struct PushConstant { + uint32_t push_constant_size; + uint32_t push_constants_vk_stage; + }; + + PushConstant push_constant; + + bool is_compute = false; + int max_output; + Vector<Set> sets; + Vector<uint32_t> set_formats; + Vector<VkPipelineShaderStageCreateInfo> pipeline_stages; + VkPipelineLayout pipeline_layout; + }; + + String _shader_uniform_debug(RID p_shader, int p_set = -1); + + RID_Owner<Shader, true> shader_owner; + + /******************/ + /**** UNIFORMS ****/ + /******************/ + + // Descriptor sets require allocation from a pool. + // The documentation on how to use pools properly + // is scarce, and the documentation is strange. + // + // Basically, you can mix and match pools as you + // like, but you'll run into fragmentation issues. + // Because of this, the recommended approach is to + // create a a pool for every descriptor set type, + // as this prevents fragmentation. + // + // This is implemented here as a having a list of + // pools (each can contain up to 64 sets) for each + // set layout. The amount of sets for each type + // is used as the key. + + enum { + MAX_DESCRIPTOR_POOL_ELEMENT = 65535 + }; + + struct DescriptorPoolKey { + union { + struct { + uint16_t uniform_type[UNIFORM_TYPE_MAX]; //using 16 bits because, for sending arrays, each element is a pool set. + }; + struct { + uint64_t key1; + uint64_t key2; + uint64_t key3; + }; + }; + bool operator<(const DescriptorPoolKey &p_key) const { + if (key1 != p_key.key1) { + return key1 < p_key.key1; + } + if (key2 != p_key.key2) { + return key2 < p_key.key2; + } + + return key3 < p_key.key3; + } + DescriptorPoolKey() { + key1 = 0; + key2 = 0; + key3 = 0; + } + }; + + struct DescriptorPool { + VkDescriptorPool pool; + uint32_t usage; + }; + + Map<DescriptorPoolKey, Set<DescriptorPool *> > descriptor_pools; + uint32_t max_descriptors_per_pool; + + DescriptorPool *_descriptor_pool_allocate(const DescriptorPoolKey &p_key); + void _descriptor_pool_free(const DescriptorPoolKey &p_key, DescriptorPool *p_pool); + + RID_Owner<Buffer, true> uniform_buffer_owner; + RID_Owner<Buffer, true> storage_buffer_owner; + + //texture buffer needs a view + struct TextureBuffer { + Buffer buffer; + VkBufferView view; + }; + + RID_Owner<TextureBuffer, true> texture_buffer_owner; + + // This structure contains the descriptor set. They _need_ to be allocated + // for a shader (and will be erased when this shader is erased), but should + // work for other shaders as long as the hash matches. This covers using + // them in shader variants. + // + // Keep also in mind that you can share buffers between descriptor sets, so + // the above restriction is not too serious. + + struct UniformSet { + uint32_t format; + RID shader_id; + uint32_t shader_set; + DescriptorPool *pool; + DescriptorPoolKey pool_key; + VkDescriptorSet descriptor_set; + //VkPipelineLayout pipeline_layout; //not owned, inherited from shader + Vector<RID> attachable_textures; //used for validation + Vector<Texture *> mutable_sampled_textures; //used for layout change + Vector<Texture *> mutable_storage_textures; //used for layout change + }; + + RID_Owner<UniformSet, true> uniform_set_owner; + + /*******************/ + /**** PIPELINES ****/ + /*******************/ + + // Render pipeline contains ALL the + // information required for drawing. + // This includes all the rasterizer state + // as well as shader used, framebuffer format, + // etc. + // While the pipeline is just a single object + // (VkPipeline) a lot of values are also saved + // here to do validation (vulkan does none by + // default) and warn the user if something + // was not supplied as intended. + + struct RenderPipeline { + //Cached values for validation +#ifdef DEBUG_ENABLED + struct Validation { + FramebufferFormatID framebuffer_format; + uint32_t dynamic_state; + VertexFormatID vertex_format; + bool uses_restart_indices; + uint32_t primitive_minimum; + uint32_t primitive_divisor; + } validation; +#endif + //Actual pipeline + RID shader; + Vector<uint32_t> set_formats; + VkPipelineLayout pipeline_layout; // not owned, needed for push constants + VkPipeline pipeline; + uint32_t push_constant_size; + uint32_t push_constant_stages; + }; + + RID_Owner<RenderPipeline, true> render_pipeline_owner; + + struct ComputePipeline { + + RID shader; + Vector<uint32_t> set_formats; + VkPipelineLayout pipeline_layout; // not owned, needed for push constants + VkPipeline pipeline; + uint32_t push_constant_size; + uint32_t push_constant_stages; + }; + + RID_Owner<ComputePipeline, true> compute_pipeline_owner; + + /*******************/ + /**** DRAW LIST ****/ + /*******************/ + + // Draw list contains both the command buffer + // used for drawing as well as a LOT of + // information used for validation. This + // validation is cheap so most of it can + // also run in release builds. + + // When using split command lists, this is + // implemented internally using secondary command + // buffers. As they can be created in threads, + // each needs it's own command pool. + + struct SplitDrawListAllocator { + VkCommandPool command_pool; + Vector<VkCommandBuffer> command_buffers; //one for each frame + }; + + Vector<SplitDrawListAllocator> split_draw_list_allocators; + + struct DrawList { + + VkCommandBuffer command_buffer; //if persistent, this is owned, otherwise it's shared with the ringbuffer + Rect2i viewport; + + struct SetState { + uint32_t pipeline_expected_format; + uint32_t uniform_set_format; + VkDescriptorSet descriptor_set; + RID uniform_set; + bool bound; + SetState() { + bound = false; + pipeline_expected_format = 0; + uniform_set_format = 0; + descriptor_set = VK_NULL_HANDLE; + } + }; + + struct State { + SetState sets[MAX_UNIFORM_SETS]; + uint32_t set_count; + RID pipeline; + RID pipeline_shader; + VkPipelineLayout pipeline_layout; + RID vertex_array; + RID index_array; + uint32_t pipeline_push_constant_stages; + + State() { + set_count = 0; + pipeline_layout = VK_NULL_HANDLE; + pipeline_push_constant_stages = 0; + } + } state; +#ifdef DEBUG_ENABLED + + struct Validation { + bool active; //means command buffer was not closes, so you can keep adding things + FramebufferFormatID framebuffer_format; + //actual render pass values + uint32_t dynamic_state; + VertexFormatID vertex_format; //INVALID_ID if not set + uint32_t vertex_array_size; //0 if not set + uint32_t vertex_max_instances_allowed; + bool index_buffer_uses_restart_indices; + uint32_t index_array_size; //0 if index buffer not set + uint32_t index_array_max_index; + uint32_t index_array_offset; + Vector<uint32_t> set_formats; + Vector<bool> set_bound; + Vector<RID> set_rids; + //last pipeline set values + bool pipeline_active; + uint32_t pipeline_dynamic_state; + VertexFormatID pipeline_vertex_format; + RID pipeline_shader; + uint32_t invalid_set_from; + bool pipeline_uses_restart_indices; + uint32_t pipeline_primitive_divisor; + uint32_t pipeline_primitive_minimum; + Vector<uint32_t> pipeline_set_formats; + uint32_t pipeline_push_constant_size; + bool pipeline_push_constant_suppplied; + + Validation() { + active = true; + dynamic_state = 0; + vertex_format = INVALID_ID; + vertex_array_size = 0; + vertex_max_instances_allowed = 0xFFFFFFFF; + framebuffer_format = INVALID_ID; + index_array_size = 0; //not sent + index_array_max_index = 0; //not set + index_buffer_uses_restart_indices = false; + invalid_set_from = 0; + + //pipeline state initalize + pipeline_active = false; + pipeline_dynamic_state = 0; + pipeline_vertex_format = INVALID_ID; + pipeline_uses_restart_indices = false; + pipeline_push_constant_size = 0; + pipeline_push_constant_suppplied = false; + } + } validation; +#else + struct Validation { + uint32_t vertex_array_size; //0 if not set + uint32_t index_array_size; //0 if index buffer not set + uint32_t index_array_offset; + + Validation() { + vertex_array_size = 0; + index_array_size = 0; //not sent + } + } validation; + +#endif + }; + + DrawList *draw_list; //one for regular draw lists, multiple for split. + uint32_t draw_list_count; + bool draw_list_split; + Vector<RID> draw_list_bound_textures; + bool draw_list_unbind_color_textures; + bool draw_list_unbind_depth_textures; + + void _draw_list_insert_clear_region(DrawList *draw_list, Framebuffer *framebuffer, Point2i viewport_offset, Point2i viewport_size, bool p_clear_color, const Vector<Color> &p_clear_colors, bool p_clear_depth, float p_depth, uint32_t p_stencil); + Error _draw_list_setup_framebuffer(Framebuffer *p_framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, VkFramebuffer *r_framebuffer, VkRenderPass *r_render_pass); + Error _draw_list_render_pass_begin(Framebuffer *framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_colors, float p_clear_depth, uint32_t p_clear_stencil, Point2i viewport_offset, Point2i viewport_size, VkFramebuffer vkframebuffer, VkRenderPass render_pass, VkCommandBuffer command_buffer, VkSubpassContents subpass_contents); + _FORCE_INLINE_ DrawList *_get_draw_list_ptr(DrawListID p_id); + + /**********************/ + /**** COMPUTE LIST ****/ + /**********************/ + + struct ComputeList { + + VkCommandBuffer command_buffer; //if persistent, this is owned, otherwise it's shared with the ringbuffer + + struct SetState { + uint32_t pipeline_expected_format; + uint32_t uniform_set_format; + VkDescriptorSet descriptor_set; + RID uniform_set; + bool bound; + SetState() { + bound = false; + pipeline_expected_format = 0; + uniform_set_format = 0; + descriptor_set = VK_NULL_HANDLE; + } + }; + + struct State { + Set<Texture *> textures_to_sampled_layout; + + SetState sets[MAX_UNIFORM_SETS]; + uint32_t set_count; + RID pipeline; + RID pipeline_shader; + VkPipelineLayout pipeline_layout; + uint32_t pipeline_push_constant_stages; + + State() { + set_count = 0; + pipeline_layout = VK_NULL_HANDLE; + pipeline_push_constant_stages = 0; + } + } state; +#ifdef DEBUG_ENABLED + + struct Validation { + bool active; //means command buffer was not closes, so you can keep adding things + Vector<uint32_t> set_formats; + Vector<bool> set_bound; + Vector<RID> set_rids; + //last pipeline set values + bool pipeline_active; + RID pipeline_shader; + uint32_t invalid_set_from; + Vector<uint32_t> pipeline_set_formats; + uint32_t pipeline_push_constant_size; + bool pipeline_push_constant_suppplied; + + Validation() { + active = true; + invalid_set_from = 0; + + //pipeline state initalize + pipeline_active = false; + pipeline_push_constant_size = 0; + pipeline_push_constant_suppplied = false; + } + } validation; +#endif + }; + + ComputeList *compute_list; + + /**************************/ + /**** FRAME MANAGEMENT ****/ + /**************************/ + + // This is the frame structure. There are normally + // 3 of these (used for triple buffering), or 2 + // (double buffering). They are cycled constantly. + // + // It contains two command buffers, one that is + // used internally for setting up (creating stuff) + // and another used mostly for drawing. + // + // They also contains a list of things that need + // to be disposed of when deleted, which can't + // happen immediately due to the asynchronous + // nature of the GPU. They will get deleted + // when the frame is cycled. + + struct Frame { + //list in usage order, from last to free to first to free + List<Buffer> buffers_to_dispose_of; + List<Texture> textures_to_dispose_of; + List<Framebuffer> framebuffers_to_dispose_of; + List<VkSampler> samplers_to_dispose_of; + List<Shader> shaders_to_dispose_of; + List<VkBufferView> buffer_views_to_dispose_of; + List<UniformSet> uniform_sets_to_dispose_of; + List<RenderPipeline> render_pipelines_to_dispose_of; + List<ComputePipeline> compute_pipelines_to_dispose_of; + + VkCommandPool command_pool; + VkCommandBuffer setup_command_buffer; //used at the begining of every frame for set-up + VkCommandBuffer draw_command_buffer; //used at the begining of every frame for set-up + + struct Timestamp { + String description; + uint64_t value; + }; + + VkQueryPool timestamp_pool; + + String *timestamp_names; + uint64_t *timestamp_cpu_values; + uint32_t timestamp_count; + String *timestamp_result_names; + uint64_t *timestamp_cpu_result_values; + uint64_t *timestamp_result_values; + uint32_t timestamp_result_count; + uint64_t index; + }; + + uint32_t max_timestamp_query_elements; + + Frame *frames; //frames available, they are cycled (usually 3) + int frame; //current frame + int frame_count; //total amount of frames + uint64_t frames_drawn; + + void _free_pending_resources(int p_frame); + + VmaAllocator allocator; + + VulkanContext *context; + + void _free_internal(RID p_id); + void _flush(bool p_current_frame); + + bool screen_prepared; + + template <class T> + void _free_rids(T &p_owner, const char *p_type); + +public: + virtual RID texture_create(const TextureFormat &p_format, const TextureView &p_view, const Vector<PoolVector<uint8_t> > &p_data = Vector<PoolVector<uint8_t> >()); + virtual RID texture_create_shared(const TextureView &p_view, RID p_with_texture); + + virtual RID texture_create_shared_from_slice(const TextureView &p_view, RID p_with_texture, uint32_t p_layer, uint32_t p_mipmap, TextureSliceType p_slice_type = TEXTURE_SLICE_2D); + virtual Error texture_update(RID p_texture, uint32_t p_layer, const PoolVector<uint8_t> &p_data, bool p_sync_with_draw = false); + virtual PoolVector<uint8_t> texture_get_data(RID p_texture, uint32_t p_layer); + + virtual bool texture_is_format_supported_for_usage(DataFormat p_format, uint32_t p_usage) const; + virtual bool texture_is_shared(RID p_texture); + virtual bool texture_is_valid(RID p_texture); + + virtual Error texture_copy(RID p_from_texture, RID p_to_texture, const Vector3 &p_from, const Vector3 &p_to, const Vector3 &p_size, uint32_t p_src_mipmap, uint32_t p_dst_mipmap, uint32_t p_src_layer, uint32_t p_dst_layer, bool p_sync_with_draw = false); + virtual Error texture_clear(RID p_texture, const Color &p_color, uint32_t p_base_mipmap, uint32_t p_mipmaps, uint32_t p_base_layer, uint32_t p_layers, bool p_sync_with_draw = false); + + /*********************/ + /**** FRAMEBUFFER ****/ + /*********************/ + + virtual FramebufferFormatID framebuffer_format_create(const Vector<AttachmentFormat> &p_format); + virtual TextureSamples framebuffer_format_get_texture_samples(FramebufferFormatID p_format); + + virtual RID framebuffer_create(const Vector<RID> &p_texture_attachments, FramebufferFormatID p_format_check = INVALID_ID); + + virtual FramebufferFormatID framebuffer_get_format(RID p_framebuffer); + + /*****************/ + /**** SAMPLER ****/ + /*****************/ + + virtual RID sampler_create(const SamplerState &p_state); + + /**********************/ + /**** VERTEX ARRAY ****/ + /**********************/ + + virtual RID vertex_buffer_create(uint32_t p_size_bytes, const PoolVector<uint8_t> &p_data = PoolVector<uint8_t>()); + + // Internally reference counted, this ID is warranted to be unique for the same description, but needs to be freed as many times as it was allocated + virtual VertexFormatID vertex_format_create(const Vector<VertexDescription> &p_vertex_formats); + virtual RID vertex_array_create(uint32_t p_vertex_count, VertexFormatID p_vertex_format, const Vector<RID> &p_src_buffers); + + virtual RID index_buffer_create(uint32_t p_size_indices, IndexBufferFormat p_format, const PoolVector<uint8_t> &p_data = PoolVector<uint8_t>(), bool p_use_restart_indices = false); + + virtual RID index_array_create(RID p_index_buffer, uint32_t p_index_offset, uint32_t p_index_count); + + /****************/ + /**** SHADER ****/ + /****************/ + + virtual RID shader_create(const Vector<ShaderStageData> &p_stages); + virtual uint32_t shader_get_vertex_input_attribute_mask(RID p_shader); + + /*****************/ + /**** UNIFORM ****/ + /*****************/ + + virtual RID uniform_buffer_create(uint32_t p_size_bytes, const PoolVector<uint8_t> &p_data = PoolVector<uint8_t>()); + virtual RID storage_buffer_create(uint32_t p_size_bytes, const PoolVector<uint8_t> &p_data = PoolVector<uint8_t>()); + virtual RID texture_buffer_create(uint32_t p_size_elements, DataFormat p_format, const PoolVector<uint8_t> &p_data = PoolVector<uint8_t>()); + + virtual RID uniform_set_create(const Vector<Uniform> &p_uniforms, RID p_shader, uint32_t p_shader_set); + virtual bool uniform_set_is_valid(RID p_uniform_set); + + virtual Error buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p_size, const void *p_data, bool p_sync_with_draw = false); //works for any buffer + virtual PoolVector<uint8_t> buffer_get_data(RID p_buffer); + + /*************************/ + /**** RENDER PIPELINE ****/ + /*************************/ + + virtual RID render_pipeline_create(RID p_shader, FramebufferFormatID p_framebuffer_format, VertexFormatID p_vertex_format, RenderPrimitive p_render_primitive, const PipelineRasterizationState &p_rasterization_state, const PipelineMultisampleState &p_multisample_state, const PipelineDepthStencilState &p_depth_stencil_state, const PipelineColorBlendState &p_blend_state, int p_dynamic_state_flags = 0); + virtual bool render_pipeline_is_valid(RID p_pipeline); + + /**************************/ + /**** COMPUTE PIPELINE ****/ + /**************************/ + + virtual RID compute_pipeline_create(RID p_shader); + virtual bool compute_pipeline_is_valid(RID p_pipeline); + + /****************/ + /**** SCREEN ****/ + /****************/ + + virtual int screen_get_width(int p_screen = 0) const; + virtual int screen_get_height(int p_screen = 0) const; + virtual FramebufferFormatID screen_get_framebuffer_format() const; + + /********************/ + /**** DRAW LISTS ****/ + /********************/ + + virtual DrawListID draw_list_begin_for_screen(int p_screen = 0, const Color &p_clear_color = Color()); + + virtual DrawListID draw_list_begin(RID p_framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values = Vector<Color>(), float p_clear_depth = 1.0, uint32_t p_clear_stencil = 0, const Rect2 &p_region = Rect2()); + virtual Error draw_list_begin_split(RID p_framebuffer, uint32_t p_splits, DrawListID *r_split_ids, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values = Vector<Color>(), float p_clear_depth = 1.0, uint32_t p_clear_stencil = 0, const Rect2 &p_region = Rect2()); + + virtual void draw_list_bind_render_pipeline(DrawListID p_list, RID p_render_pipeline); + virtual void draw_list_bind_uniform_set(DrawListID p_list, RID p_uniform_set, uint32_t p_index); + virtual void draw_list_bind_vertex_array(DrawListID p_list, RID p_vertex_array); + virtual void draw_list_bind_index_array(DrawListID p_list, RID p_index_array); + virtual void draw_list_set_line_width(DrawListID p_list, float p_width); + virtual void draw_list_set_push_constant(DrawListID p_list, void *p_data, uint32_t p_data_size); + + virtual void draw_list_draw(DrawListID p_list, bool p_use_indices, uint32_t p_instances = 1, uint32_t p_procedural_vertices = 0); + + virtual void draw_list_enable_scissor(DrawListID p_list, const Rect2 &p_rect); + virtual void draw_list_disable_scissor(DrawListID p_list); + + virtual void draw_list_end(); + + /***********************/ + /**** COMPUTE LISTS ****/ + /***********************/ + + virtual ComputeListID compute_list_begin(); + virtual void compute_list_bind_compute_pipeline(ComputeListID p_list, RID p_compute_pipeline); + virtual void compute_list_bind_uniform_set(ComputeListID p_list, RID p_uniform_set, uint32_t p_index); + virtual void compute_list_set_push_constant(ComputeListID p_list, void *p_data, uint32_t p_data_size); + virtual void compute_list_add_barrier(ComputeListID p_list); + + virtual void compute_list_dispatch(ComputeListID p_list, uint32_t p_x_groups, uint32_t p_y_groups, uint32_t p_z_groups); + virtual void compute_list_end(); + + /**************/ + /**** FREE ****/ + /**************/ + + virtual void free(RID p_id); + + /****************/ + /**** Timing ****/ + /****************/ + + virtual void capture_timestamp(const String &p_name, bool p_sync_to_draw); + virtual uint32_t get_captured_timestamps_count() const; + virtual uint64_t get_captured_timestamps_frame() const; + virtual uint64_t get_captured_timestamp_gpu_time(uint32_t p_index) const; + virtual uint64_t get_captured_timestamp_cpu_time(uint32_t p_index) const; + virtual String get_captured_timestamp_name(uint32_t p_index) const; + + /****************/ + /**** Limits ****/ + /****************/ + + virtual int limit_get(Limit p_limit); + + virtual void prepare_screen_for_drawing(); + void initialize(VulkanContext *p_context); + void finalize(); + + virtual void swap_buffers(); + + virtual uint32_t get_frame_delay() const; + + RenderingDeviceVulkan(); +}; + +#endif // RENDERING_DEVICE_VULKAN_H diff --git a/drivers/vulkan/vulkan_context.cpp b/drivers/vulkan/vulkan_context.cpp new file mode 100644 index 0000000000..ca488fc3a3 --- /dev/null +++ b/drivers/vulkan/vulkan_context.cpp @@ -0,0 +1,1505 @@ +/*************************************************************************/ +/* vulkan_context.cpp */ +/*************************************************************************/ +/* 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. */ +/*************************************************************************/ + +#include "vulkan_context.h" +#include "core/engine.h" +#include "core/print_string.h" +#include "core/project_settings.h" +#include "core/version.h" +#include "vk_enum_string_helper.h" +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) +#define VULKAN_DEBUG(m_text) print_line(m_text) +#define APP_SHORT_NAME "GodotEngine" + +VKAPI_ATTR VkBool32 VKAPI_CALL VulkanContext::_debug_messenger_callback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, + VkDebugUtilsMessageTypeFlagsEXT messageType, + const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData, + void *pUserData) { + char prefix[64] = ""; + char *message = (char *)malloc(strlen(pCallbackData->pMessage) + 5000); + ERR_FAIL_COND_V(!message, false); + + //This error needs to be ignored because the AMD allocator will mix up memory types on IGP processors + if (strstr(pCallbackData->pMessage, "Mapping an image with layout") != NULL && + strstr(pCallbackData->pMessage, "can result in undefined behavior if this memory is used by the device") != NULL) { + free(message); + return VK_FALSE; + } + // This needs to be ignored because Validator is wrong here + if (strstr(pCallbackData->pMessage, "SPIR-V module not valid: Pointer operand") != NULL && + strstr(pCallbackData->pMessage, "must be a memory object") != NULL) { + free(message); + return VK_FALSE; + } + if (strstr(pCallbackData->pMessageIdName, "UNASSIGNED-CoreValidation-DrawState-ClearCmdBeforeDraw") != NULL) { + free(message); + return VK_FALSE; + } + + if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT) { + strcat(prefix, "VERBOSE : "); + } else if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT) { + strcat(prefix, "INFO : "); + } else if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) { + strcat(prefix, "WARNING : "); + } else if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) { + strcat(prefix, "ERROR : "); + } + + if (messageType & VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT) { + strcat(prefix, "GENERAL"); + } else { + if (messageType & VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT) { + strcat(prefix, "VALIDATION"); + //validation_error = 1; + } + if (messageType & VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT) { + if (messageType & VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT) { + strcat(prefix, "|"); + } + strcat(prefix, "PERFORMANCE"); + } + } + + sprintf(message, "%s - Message Id Number: %d | Message Id Name: %s\n\t%s\n", prefix, pCallbackData->messageIdNumber, + pCallbackData->pMessageIdName, pCallbackData->pMessage); + + if (pCallbackData->objectCount > 0) { + char tmp_message[500]; + sprintf(tmp_message, "\n\tObjects - %d\n", pCallbackData->objectCount); + strcat(message, tmp_message); + for (uint32_t object = 0; object < pCallbackData->objectCount; ++object) { + if (NULL != pCallbackData->pObjects[object].pObjectName && strlen(pCallbackData->pObjects[object].pObjectName) > 0) { + sprintf(tmp_message, "\t\tObject[%d] - %s, Handle %p, Name \"%s\"\n", object, + string_VkObjectType(pCallbackData->pObjects[object].objectType), + (void *)(pCallbackData->pObjects[object].objectHandle), pCallbackData->pObjects[object].pObjectName); + } else { + sprintf(tmp_message, "\t\tObject[%d] - %s, Handle %p\n", object, + string_VkObjectType(pCallbackData->pObjects[object].objectType), + (void *)(pCallbackData->pObjects[object].objectHandle)); + } + strcat(message, tmp_message); + } + } + if (pCallbackData->cmdBufLabelCount > 0) { + char tmp_message[500]; + sprintf(tmp_message, "\n\tCommand Buffer Labels - %d\n", pCallbackData->cmdBufLabelCount); + strcat(message, tmp_message); + for (uint32_t cmd_buf_label = 0; cmd_buf_label < pCallbackData->cmdBufLabelCount; ++cmd_buf_label) { + sprintf(tmp_message, "\t\tLabel[%d] - %s { %f, %f, %f, %f}\n", cmd_buf_label, + pCallbackData->pCmdBufLabels[cmd_buf_label].pLabelName, pCallbackData->pCmdBufLabels[cmd_buf_label].color[0], + pCallbackData->pCmdBufLabels[cmd_buf_label].color[1], pCallbackData->pCmdBufLabels[cmd_buf_label].color[2], + pCallbackData->pCmdBufLabels[cmd_buf_label].color[3]); + strcat(message, tmp_message); + } + } + + ERR_PRINT(message); + + free(message); + + if (Engine::get_singleton()->is_abort_on_gpu_errors_enabled()) { + abort(); + } + // Don't bail out, but keep going. + return false; +} + +VkBool32 VulkanContext::_check_layers(uint32_t check_count, const char **check_names, uint32_t layer_count, VkLayerProperties *layers) { + for (uint32_t i = 0; i < check_count; i++) { + VkBool32 found = 0; + for (uint32_t j = 0; j < layer_count; j++) { + if (!strcmp(check_names[i], layers[j].layerName)) { + found = 1; + break; + } + } + if (!found) { + ERR_PRINT("Cant find layer: " + String(check_names[i])); + return 0; + } + } + return 1; +} + +Error VulkanContext::_create_validation_layers() { + + VkResult err; + uint32_t instance_layer_count = 0; + uint32_t validation_layer_count = 0; + const char *instance_validation_layers_alt1[] = { "VK_LAYER_LUNARG_standard_validation" }; + const char *instance_validation_layers_alt2[] = { "VK_LAYER_GOOGLE_threading", "VK_LAYER_LUNARG_parameter_validation", + "VK_LAYER_LUNARG_object_tracker", "VK_LAYER_LUNARG_core_validation", + "VK_LAYER_GOOGLE_unique_objects" }; + VkBool32 validation_found = 0; + err = vkEnumerateInstanceLayerProperties(&instance_layer_count, NULL); + ERR_FAIL_COND_V(err, ERR_CANT_CREATE); + const char **instance_validation_layers = instance_validation_layers_alt1; + if (instance_layer_count > 0) { + VkLayerProperties *instance_layers = (VkLayerProperties *)malloc(sizeof(VkLayerProperties) * instance_layer_count); + err = vkEnumerateInstanceLayerProperties(&instance_layer_count, instance_layers); + if (err) { + free(instance_layers); + ERR_FAIL_V(ERR_CANT_CREATE); + } + + validation_found = _check_layers(ARRAY_SIZE(instance_validation_layers_alt1), instance_validation_layers, + instance_layer_count, instance_layers); + if (validation_found) { + enabled_layer_count = ARRAY_SIZE(instance_validation_layers_alt1); + enabled_layers[0] = "VK_LAYER_LUNARG_standard_validation"; + validation_layer_count = 1; + } else { + // use alternative set of validation layers + instance_validation_layers = instance_validation_layers_alt2; + enabled_layer_count = ARRAY_SIZE(instance_validation_layers_alt2); + validation_found = _check_layers(ARRAY_SIZE(instance_validation_layers_alt2), instance_validation_layers, + instance_layer_count, instance_layers); + validation_layer_count = ARRAY_SIZE(instance_validation_layers_alt2); + for (uint32_t i = 0; i < validation_layer_count; i++) { + enabled_layers[i] = instance_validation_layers[i]; + } + } + free(instance_layers); + } + + if (!validation_found) { + return ERR_CANT_CREATE; + } + + return OK; +} + +Error VulkanContext::_initialize_extensions() { + + VkResult err; + uint32_t instance_extension_count = 0; + + enabled_extension_count = 0; + enabled_layer_count = 0; + /* Look for instance extensions */ + VkBool32 surfaceExtFound = 0; + VkBool32 platformSurfaceExtFound = 0; + memset(extension_names, 0, sizeof(extension_names)); + + err = vkEnumerateInstanceExtensionProperties(NULL, &instance_extension_count, NULL); + ERR_FAIL_COND_V(err, ERR_CANT_CREATE); + + if (instance_extension_count > 0) { + VkExtensionProperties *instance_extensions = (VkExtensionProperties *)malloc(sizeof(VkExtensionProperties) * instance_extension_count); + err = vkEnumerateInstanceExtensionProperties(NULL, &instance_extension_count, instance_extensions); + if (err) { + free(instance_extensions); + ERR_FAIL_V(ERR_CANT_CREATE); + } + for (uint32_t i = 0; i < instance_extension_count; i++) { + if (!strcmp(VK_KHR_SURFACE_EXTENSION_NAME, instance_extensions[i].extensionName)) { + surfaceExtFound = 1; + extension_names[enabled_extension_count++] = VK_KHR_SURFACE_EXTENSION_NAME; + } + + if (!strcmp(_get_platform_surface_extension(), instance_extensions[i].extensionName)) { + platformSurfaceExtFound = 1; + extension_names[enabled_extension_count++] = _get_platform_surface_extension(); + } + if (!strcmp(VK_EXT_DEBUG_REPORT_EXTENSION_NAME, instance_extensions[i].extensionName)) { + if (use_validation_layers) { + extension_names[enabled_extension_count++] = VK_EXT_DEBUG_REPORT_EXTENSION_NAME; + } + } + if (!strcmp(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, instance_extensions[i].extensionName)) { + if (use_validation_layers) { + extension_names[enabled_extension_count++] = VK_EXT_DEBUG_UTILS_EXTENSION_NAME; + } + } + if (enabled_extension_count >= MAX_EXTENSIONS) { + free(instance_extensions); + ERR_FAIL_V_MSG(ERR_BUG, "Enabled extension count reaches MAX_EXTENSIONS, BUG"); + } + } + + free(instance_extensions); + } + + ERR_FAIL_COND_V_MSG(!surfaceExtFound, ERR_CANT_CREATE, "No surface extension found, is a driver installed?"); + ERR_FAIL_COND_V_MSG(!platformSurfaceExtFound, ERR_CANT_CREATE, "No platform surface extension found, is a driver installed?"); + + return OK; +} + +Error VulkanContext::_create_physical_device() { + + /* Look for validation layers */ + if (use_validation_layers) { + _create_validation_layers(); + } + + { + Error err = _initialize_extensions(); + if (err != OK) { + return err; + } + } + + CharString cs = ProjectSettings::get_singleton()->get("application/config/name").operator String().utf8(); + String name = "GodotEngine " + String(VERSION_FULL_NAME); + CharString namecs = name.utf8(); + const VkApplicationInfo app = { + /*sType*/ VK_STRUCTURE_TYPE_APPLICATION_INFO, + /*pNext*/ NULL, + /*pApplicationName*/ cs.get_data(), + /*applicationVersion*/ 0, + /*pEngineName*/ namecs.get_data(), + /*engineVersion*/ 0, + /*apiVersion*/ VK_API_VERSION_1_0, + }; + VkInstanceCreateInfo inst_info = { + /*sType*/ VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, + /*pNext*/ NULL, + /*flags*/ 0, + /*pApplicationInfo*/ &app, + /*enabledLayerCount*/ enabled_layer_count, + /*ppEnabledLayerNames*/ (const char *const *)instance_validation_layers, + /*enabledExtensionCount*/ enabled_extension_count, + /*ppEnabledExtensionNames*/ (const char *const *)extension_names, + }; + + /* + * This is info for a temp callback to use during CreateInstance. + * After the instance is created, we use the instance-based + * function to register the final callback. + */ + VkDebugUtilsMessengerCreateInfoEXT dbg_messenger_create_info; + if (use_validation_layers) { + // VK_EXT_debug_utils style + dbg_messenger_create_info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT; + dbg_messenger_create_info.pNext = NULL; + dbg_messenger_create_info.flags = 0; + dbg_messenger_create_info.messageSeverity = + VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT; + dbg_messenger_create_info.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT; + dbg_messenger_create_info.pfnUserCallback = _debug_messenger_callback; + dbg_messenger_create_info.pUserData = this; + inst_info.pNext = &dbg_messenger_create_info; + } + + uint32_t gpu_count; + + VkResult err = vkCreateInstance(&inst_info, NULL, &inst); + ERR_FAIL_COND_V_MSG(err == VK_ERROR_INCOMPATIBLE_DRIVER, ERR_CANT_CREATE, + "Cannot find a compatible Vulkan installable client driver (ICD).\n\n" + "vkCreateInstance Failure"); + ERR_FAIL_COND_V_MSG(err == VK_ERROR_EXTENSION_NOT_PRESENT, ERR_CANT_CREATE, + "Cannot find a specified extension library.\n" + "Make sure your layers path is set appropriately.\n" + "vkCreateInstance Failure"); + ERR_FAIL_COND_V_MSG(err, ERR_CANT_CREATE, + "vkCreateInstance failed.\n\n" + "Do you have a compatible Vulkan installable client driver (ICD) installed?\n" + "Please look at the Getting Started guide for additional information.\n" + "vkCreateInstance Failure"); + + /* Make initial call to query gpu_count, then second call for gpu info*/ + err = vkEnumeratePhysicalDevices(inst, &gpu_count, NULL); + ERR_FAIL_COND_V(err, ERR_CANT_CREATE); + + ERR_FAIL_COND_V_MSG(gpu_count == 0, ERR_CANT_CREATE, + "vkEnumeratePhysicalDevices reported zero accessible devices.\n\n" + "Do you have a compatible Vulkan installable client driver (ICD) installed?\n" + "vkEnumeratePhysicalDevices Failure"); + + VkPhysicalDevice *physical_devices = (VkPhysicalDevice *)malloc(sizeof(VkPhysicalDevice) * gpu_count); + err = vkEnumeratePhysicalDevices(inst, &gpu_count, physical_devices); + if (err) { + free(physical_devices); + ERR_FAIL_V(ERR_CANT_CREATE); + } + /* for now, just grab the first physical device */ + gpu = physical_devices[0]; + free(physical_devices); + + /* Look for device extensions */ + uint32_t device_extension_count = 0; + VkBool32 swapchainExtFound = 0; + enabled_extension_count = 0; + memset(extension_names, 0, sizeof(extension_names)); + + err = vkEnumerateDeviceExtensionProperties(gpu, NULL, &device_extension_count, NULL); + ERR_FAIL_COND_V(err, ERR_CANT_CREATE); + + if (device_extension_count > 0) { + VkExtensionProperties *device_extensions = (VkExtensionProperties *)malloc(sizeof(VkExtensionProperties) * device_extension_count); + err = vkEnumerateDeviceExtensionProperties(gpu, NULL, &device_extension_count, device_extensions); + if (err) { + free(device_extensions); + ERR_FAIL_V(ERR_CANT_CREATE); + } + + for (uint32_t i = 0; i < device_extension_count; i++) { + if (!strcmp(VK_KHR_SWAPCHAIN_EXTENSION_NAME, device_extensions[i].extensionName)) { + swapchainExtFound = 1; + extension_names[enabled_extension_count++] = VK_KHR_SWAPCHAIN_EXTENSION_NAME; + } + if (enabled_extension_count >= MAX_EXTENSIONS) { + free(device_extensions); + ERR_FAIL_V_MSG(ERR_BUG, "Enabled extension count reaches MAX_EXTENSIONS, BUG"); + } + } + + if (VK_KHR_incremental_present_enabled) { + // Even though the user "enabled" the extension via the command + // line, we must make sure that it's enumerated for use with the + // device. Therefore, disable it here, and re-enable it again if + // enumerated. + VK_KHR_incremental_present_enabled = false; + for (uint32_t i = 0; i < device_extension_count; i++) { + if (!strcmp(VK_KHR_INCREMENTAL_PRESENT_EXTENSION_NAME, device_extensions[i].extensionName)) { + extension_names[enabled_extension_count++] = VK_KHR_INCREMENTAL_PRESENT_EXTENSION_NAME; + VK_KHR_incremental_present_enabled = true; + VULKAN_DEBUG("VK_KHR_incremental_present extension enabled\n"); + } + if (enabled_extension_count >= MAX_EXTENSIONS) { + free(device_extensions); + ERR_FAIL_V_MSG(ERR_BUG, "Enabled extension count reaches MAX_EXTENSIONS, BUG"); + } + } + if (!VK_KHR_incremental_present_enabled) { + VULKAN_DEBUG("VK_KHR_incremental_present extension NOT AVAILABLE\n"); + } + } + + if (VK_GOOGLE_display_timing_enabled) { + // Even though the user "enabled" the extension via the command + // line, we must make sure that it's enumerated for use with the + // device. Therefore, disable it here, and re-enable it again if + // enumerated. + VK_GOOGLE_display_timing_enabled = false; + for (uint32_t i = 0; i < device_extension_count; i++) { + if (!strcmp(VK_GOOGLE_DISPLAY_TIMING_EXTENSION_NAME, device_extensions[i].extensionName)) { + extension_names[enabled_extension_count++] = VK_GOOGLE_DISPLAY_TIMING_EXTENSION_NAME; + VK_GOOGLE_display_timing_enabled = true; + VULKAN_DEBUG("VK_GOOGLE_display_timing extension enabled\n"); + } + if (enabled_extension_count >= MAX_EXTENSIONS) { + free(device_extensions); + ERR_FAIL_V_MSG(ERR_BUG, "Enabled extension count reaches MAX_EXTENSIONS, BUG"); + } + } + if (!VK_GOOGLE_display_timing_enabled) { + VULKAN_DEBUG("VK_GOOGLE_display_timing extension NOT AVAILABLE\n"); + } + } + + free(device_extensions); + } + + ERR_FAIL_COND_V_MSG(!swapchainExtFound, ERR_CANT_CREATE, + "vkEnumerateDeviceExtensionProperties failed to find the " VK_KHR_SWAPCHAIN_EXTENSION_NAME + " extension.\n\nDo you have a compatible Vulkan installable client driver (ICD) installed?\n" + "vkCreateInstance Failure"); + + if (use_validation_layers) { + // Setup VK_EXT_debug_utils function pointers always (we use them for + // debug labels and names). + CreateDebugUtilsMessengerEXT = + (PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr(inst, "vkCreateDebugUtilsMessengerEXT"); + DestroyDebugUtilsMessengerEXT = + (PFN_vkDestroyDebugUtilsMessengerEXT)vkGetInstanceProcAddr(inst, "vkDestroyDebugUtilsMessengerEXT"); + SubmitDebugUtilsMessageEXT = + (PFN_vkSubmitDebugUtilsMessageEXT)vkGetInstanceProcAddr(inst, "vkSubmitDebugUtilsMessageEXT"); + CmdBeginDebugUtilsLabelEXT = + (PFN_vkCmdBeginDebugUtilsLabelEXT)vkGetInstanceProcAddr(inst, "vkCmdBeginDebugUtilsLabelEXT"); + CmdEndDebugUtilsLabelEXT = + (PFN_vkCmdEndDebugUtilsLabelEXT)vkGetInstanceProcAddr(inst, "vkCmdEndDebugUtilsLabelEXT"); + CmdInsertDebugUtilsLabelEXT = + (PFN_vkCmdInsertDebugUtilsLabelEXT)vkGetInstanceProcAddr(inst, "vkCmdInsertDebugUtilsLabelEXT"); + SetDebugUtilsObjectNameEXT = + (PFN_vkSetDebugUtilsObjectNameEXT)vkGetInstanceProcAddr(inst, "vkSetDebugUtilsObjectNameEXT"); + if (NULL == CreateDebugUtilsMessengerEXT || NULL == DestroyDebugUtilsMessengerEXT || + NULL == SubmitDebugUtilsMessageEXT || NULL == CmdBeginDebugUtilsLabelEXT || + NULL == CmdEndDebugUtilsLabelEXT || NULL == CmdInsertDebugUtilsLabelEXT || + NULL == SetDebugUtilsObjectNameEXT) { + ERR_FAIL_V_MSG(ERR_CANT_CREATE, + "GetProcAddr: Failed to init VK_EXT_debug_utils\n" + "GetProcAddr: Failure"); + } + + err = CreateDebugUtilsMessengerEXT(inst, &dbg_messenger_create_info, NULL, &dbg_messenger); + switch (err) { + case VK_SUCCESS: + break; + case VK_ERROR_OUT_OF_HOST_MEMORY: + ERR_FAIL_V_MSG(ERR_CANT_CREATE, + "CreateDebugUtilsMessengerEXT: out of host memory\n" + "CreateDebugUtilsMessengerEXT Failure"); + break; + default: + ERR_FAIL_V_MSG(ERR_CANT_CREATE, + "CreateDebugUtilsMessengerEXT: unknown failure\n" + "CreateDebugUtilsMessengerEXT Failure"); + ERR_FAIL_V(ERR_CANT_CREATE); + break; + } + } + vkGetPhysicalDeviceProperties(gpu, &gpu_props); + + /* Call with NULL data to get count */ + vkGetPhysicalDeviceQueueFamilyProperties(gpu, &queue_family_count, NULL); + ERR_FAIL_COND_V(queue_family_count == 0, ERR_CANT_CREATE); + + queue_props = (VkQueueFamilyProperties *)malloc(queue_family_count * sizeof(VkQueueFamilyProperties)); + vkGetPhysicalDeviceQueueFamilyProperties(gpu, &queue_family_count, queue_props); + + // Query fine-grained feature support for this device. + // If app has specific feature requirements it should check supported + // features based on this query + vkGetPhysicalDeviceFeatures(gpu, &physical_device_features); + +#define GET_INSTANCE_PROC_ADDR(inst, entrypoint) \ + { \ + fp##entrypoint = (PFN_vk##entrypoint)vkGetInstanceProcAddr(inst, "vk" #entrypoint); \ + ERR_FAIL_COND_V_MSG(fp##entrypoint == NULL, ERR_CANT_CREATE, \ + "vkGetInstanceProcAddr failed to find vk" #entrypoint); \ + } + + GET_INSTANCE_PROC_ADDR(inst, GetPhysicalDeviceSurfaceSupportKHR); + GET_INSTANCE_PROC_ADDR(inst, GetPhysicalDeviceSurfaceCapabilitiesKHR); + GET_INSTANCE_PROC_ADDR(inst, GetPhysicalDeviceSurfaceFormatsKHR); + GET_INSTANCE_PROC_ADDR(inst, GetPhysicalDeviceSurfacePresentModesKHR); + GET_INSTANCE_PROC_ADDR(inst, GetSwapchainImagesKHR); + + return OK; +} + +Error VulkanContext::_create_device() { + + VkResult err; + float queue_priorities[1] = { 0.0 }; + VkDeviceQueueCreateInfo queues[2]; + queues[0].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; + queues[0].pNext = NULL; + queues[0].queueFamilyIndex = graphics_queue_family_index; + queues[0].queueCount = 1; + queues[0].pQueuePriorities = queue_priorities; + queues[0].flags = 0; + + VkDeviceCreateInfo sdevice = { + /*sType*/ VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, + /*pNext*/ NULL, + /*flags*/ 0, + /*queueCreateInfoCount*/ 1, + /*pQueueCreateInfos*/ queues, + /*enabledLayerCount*/ 0, + /*ppEnabledLayerNames*/ NULL, + /*enabledExtensionCount*/ enabled_extension_count, + /*ppEnabledExtensionNames*/ (const char *const *)extension_names, + /*pEnabledFeatures*/ &physical_device_features, // If specific features are required, pass them in here + + }; + if (separate_present_queue) { + queues[1].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; + queues[1].pNext = NULL; + queues[1].queueFamilyIndex = present_queue_family_index; + queues[1].queueCount = 1; + queues[1].pQueuePriorities = queue_priorities; + queues[1].flags = 0; + sdevice.queueCreateInfoCount = 2; + } + err = vkCreateDevice(gpu, &sdevice, NULL, &device); + ERR_FAIL_COND_V(err, ERR_CANT_CREATE); + return OK; +} + +Error VulkanContext::_initialize_queues(VkSurfaceKHR surface) { + + // Iterate over each queue to learn whether it supports presenting: + VkBool32 *supportsPresent = (VkBool32 *)malloc(queue_family_count * sizeof(VkBool32)); + for (uint32_t i = 0; i < queue_family_count; i++) { + fpGetPhysicalDeviceSurfaceSupportKHR(gpu, i, surface, &supportsPresent[i]); + } + + // Search for a graphics and a present queue in the array of queue + // families, try to find one that supports both + uint32_t graphicsQueueFamilyIndex = UINT32_MAX; + uint32_t presentQueueFamilyIndex = UINT32_MAX; + for (uint32_t i = 0; i < queue_family_count; i++) { + if ((queue_props[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0) { + if (graphicsQueueFamilyIndex == UINT32_MAX) { + graphicsQueueFamilyIndex = i; + } + + if (supportsPresent[i] == VK_TRUE) { + graphicsQueueFamilyIndex = i; + presentQueueFamilyIndex = i; + break; + } + } + } + + if (presentQueueFamilyIndex == UINT32_MAX) { + // If didn't find a queue that supports both graphics and present, then + // find a separate present queue. + for (uint32_t i = 0; i < queue_family_count; ++i) { + if (supportsPresent[i] == VK_TRUE) { + presentQueueFamilyIndex = i; + break; + } + } + } + + free(supportsPresent); + + // Generate error if could not find both a graphics and a present queue + ERR_FAIL_COND_V_MSG(graphicsQueueFamilyIndex == UINT32_MAX || presentQueueFamilyIndex == UINT32_MAX, ERR_CANT_CREATE, + "Could not find both graphics and present queues\n"); + + graphics_queue_family_index = graphicsQueueFamilyIndex; + present_queue_family_index = presentQueueFamilyIndex; + separate_present_queue = (graphics_queue_family_index != present_queue_family_index); + + _create_device(); + + static PFN_vkGetDeviceProcAddr g_gdpa = NULL; +#define GET_DEVICE_PROC_ADDR(dev, entrypoint) \ + { \ + if (!g_gdpa) g_gdpa = (PFN_vkGetDeviceProcAddr)vkGetInstanceProcAddr(inst, "vkGetDeviceProcAddr"); \ + fp##entrypoint = (PFN_vk##entrypoint)g_gdpa(dev, "vk" #entrypoint); \ + ERR_FAIL_COND_V_MSG(fp##entrypoint == NULL, ERR_CANT_CREATE, \ + "vkGetDeviceProcAddr failed to find vk" #entrypoint); \ + } + + GET_DEVICE_PROC_ADDR(device, CreateSwapchainKHR); + GET_DEVICE_PROC_ADDR(device, DestroySwapchainKHR); + GET_DEVICE_PROC_ADDR(device, GetSwapchainImagesKHR); + GET_DEVICE_PROC_ADDR(device, AcquireNextImageKHR); + GET_DEVICE_PROC_ADDR(device, QueuePresentKHR); + if (VK_GOOGLE_display_timing_enabled) { + GET_DEVICE_PROC_ADDR(device, GetRefreshCycleDurationGOOGLE); + GET_DEVICE_PROC_ADDR(device, GetPastPresentationTimingGOOGLE); + } + + vkGetDeviceQueue(device, graphics_queue_family_index, 0, &graphics_queue); + + if (!separate_present_queue) { + present_queue = graphics_queue; + } else { + vkGetDeviceQueue(device, present_queue_family_index, 0, &present_queue); + } + + // Get the list of VkFormat's that are supported: + uint32_t formatCount; + VkResult err = fpGetPhysicalDeviceSurfaceFormatsKHR(gpu, surface, &formatCount, NULL); + ERR_FAIL_COND_V(err, ERR_CANT_CREATE); + VkSurfaceFormatKHR *surfFormats = (VkSurfaceFormatKHR *)malloc(formatCount * sizeof(VkSurfaceFormatKHR)); + err = fpGetPhysicalDeviceSurfaceFormatsKHR(gpu, surface, &formatCount, surfFormats); + if (err) { + free(surfFormats); + ERR_FAIL_V(ERR_CANT_CREATE); + } + // If the format list includes just one entry of VK_FORMAT_UNDEFINED, + // the surface has no preferred format. Otherwise, at least one + // supported format will be returned. + if (true || (formatCount == 1 && surfFormats[0].format == VK_FORMAT_UNDEFINED)) { + format = VK_FORMAT_B8G8R8A8_UNORM; + } else { + if (formatCount < 1) { + free(surfFormats); + ERR_FAIL_V_MSG(ERR_CANT_CREATE, "formatCount less than 1"); + } + format = surfFormats[0].format; + } + color_space = surfFormats[0].colorSpace; + + free(surfFormats); + + Error serr = _create_semaphores(); + if (serr) { + return serr; + } + + queues_initialized = true; + return OK; +} + +Error VulkanContext::_create_semaphores() { + VkResult err; + + // Create semaphores to synchronize acquiring presentable buffers before + // rendering and waiting for drawing to be complete before presenting + VkSemaphoreCreateInfo semaphoreCreateInfo = { + /*sType*/ VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, + /*pNext*/ NULL, + /*flags*/ 0, + }; + + // Create fences that we can use to throttle if we get too far + // ahead of the image presents + VkFenceCreateInfo fence_ci = { + /*sType*/ VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, + /*pNext*/ NULL, + /*flags*/ VK_FENCE_CREATE_SIGNALED_BIT + }; + for (uint32_t i = 0; i < FRAME_LAG; i++) { + err = vkCreateFence(device, &fence_ci, NULL, &fences[i]); + ERR_FAIL_COND_V(err, ERR_CANT_CREATE); + + err = vkCreateSemaphore(device, &semaphoreCreateInfo, NULL, &image_acquired_semaphores[i]); + ERR_FAIL_COND_V(err, ERR_CANT_CREATE); + + err = vkCreateSemaphore(device, &semaphoreCreateInfo, NULL, &draw_complete_semaphores[i]); + ERR_FAIL_COND_V(err, ERR_CANT_CREATE); + + if (separate_present_queue) { + err = vkCreateSemaphore(device, &semaphoreCreateInfo, NULL, &image_ownership_semaphores[i]); + ERR_FAIL_COND_V(err, ERR_CANT_CREATE); + } + } + frame_index = 0; + + // Get Memory information and properties + vkGetPhysicalDeviceMemoryProperties(gpu, &memory_properties); + + return OK; +} + +int VulkanContext::_window_create(VkSurfaceKHR p_surface, int p_width, int p_height) { + + if (!queues_initialized) { + // We use a single GPU, but we need a surface to initialize the + // queues, so this process must be deferred until a surface + // is created. + _initialize_queues(p_surface); + } + + Window window; + window.surface = p_surface; + window.width = p_width; + window.height = p_height; + Error err = _update_swap_chain(&window); + ERR_FAIL_COND_V(err != OK, -1); + + int id = last_window_id; + windows[id] = window; + last_window_id++; + return id; +} + +void VulkanContext::window_resize(int p_window, int p_width, int p_height) { + ERR_FAIL_COND(!windows.has(p_window)); + windows[p_window].width = p_width; + windows[p_window].height = p_height; + _update_swap_chain(&windows[p_window]); +} + +int VulkanContext::window_get_width(int p_window) { + ERR_FAIL_COND_V(!windows.has(p_window), -1); + return windows[p_window].width; +} + +int VulkanContext::window_get_height(int p_window) { + ERR_FAIL_COND_V(!windows.has(p_window), -1); + return windows[p_window].height; +} + +VkRenderPass VulkanContext::window_get_render_pass(int p_window) { + ERR_FAIL_COND_V(!windows.has(p_window), VK_NULL_HANDLE); + Window *w = &windows[p_window]; + //vulkan use of currentbuffer + return w->render_pass; +} + +VkFramebuffer VulkanContext::window_get_framebuffer(int p_window) { + ERR_FAIL_COND_V(!windows.has(p_window), VK_NULL_HANDLE); + ERR_FAIL_COND_V(!buffers_prepared, VK_NULL_HANDLE); + Window *w = &windows[p_window]; + //vulkan use of currentbuffer + return w->swapchain_image_resources[w->current_buffer].framebuffer; +} + +void VulkanContext::window_destroy(int p_window_id) { + ERR_FAIL_COND(!windows.has(p_window_id)); + _clean_up_swap_chain(&windows[p_window_id]); + vkDestroySurfaceKHR(inst, windows[p_window_id].surface, NULL); + windows.erase(p_window_id); +} + +Error VulkanContext::_clean_up_swap_chain(Window *window) { + + if (!window->swapchain) { + return OK; + } + vkDeviceWaitIdle(device); + + //this destroys images associated it seems + fpDestroySwapchainKHR(device, window->swapchain, NULL); + window->swapchain = VK_NULL_HANDLE; + vkDestroyRenderPass(device, window->render_pass, NULL); + if (window->swapchain_image_resources) { + for (uint32_t i = 0; i < swapchainImageCount; i++) { + vkDestroyImageView(device, window->swapchain_image_resources[i].view, NULL); + vkDestroyFramebuffer(device, window->swapchain_image_resources[i].framebuffer, NULL); + } + + free(window->swapchain_image_resources); + window->swapchain_image_resources = NULL; + } + if (separate_present_queue) { + vkDestroyCommandPool(device, window->present_cmd_pool, NULL); + } + return OK; +} + +Error VulkanContext::_update_swap_chain(Window *window) { + VkResult err; + + if (window->swapchain) { + _clean_up_swap_chain(window); + } + + // Check the surface capabilities and formats + VkSurfaceCapabilitiesKHR surfCapabilities; + err = fpGetPhysicalDeviceSurfaceCapabilitiesKHR(gpu, window->surface, &surfCapabilities); + ERR_FAIL_COND_V(err, ERR_CANT_CREATE); + + uint32_t presentModeCount; + err = fpGetPhysicalDeviceSurfacePresentModesKHR(gpu, window->surface, &presentModeCount, NULL); + ERR_FAIL_COND_V(err, ERR_CANT_CREATE); + VkPresentModeKHR *presentModes = (VkPresentModeKHR *)malloc(presentModeCount * sizeof(VkPresentModeKHR)); + ERR_FAIL_COND_V(!presentModes, ERR_CANT_CREATE); + err = fpGetPhysicalDeviceSurfacePresentModesKHR(gpu, window->surface, &presentModeCount, presentModes); + if (err) { + free(presentModes); + ERR_FAIL_V(ERR_CANT_CREATE); + } + + VkExtent2D swapchainExtent; + // width and height are either both 0xFFFFFFFF, or both not 0xFFFFFFFF. + if (surfCapabilities.currentExtent.width == 0xFFFFFFFF) { + // If the surface size is undefined, the size is set to the size + // of the images requested, which must fit within the minimum and + // maximum values. + swapchainExtent.width = window->width; + swapchainExtent.height = window->height; + + if (swapchainExtent.width < surfCapabilities.minImageExtent.width) { + swapchainExtent.width = surfCapabilities.minImageExtent.width; + } else if (swapchainExtent.width > surfCapabilities.maxImageExtent.width) { + swapchainExtent.width = surfCapabilities.maxImageExtent.width; + } + + if (swapchainExtent.height < surfCapabilities.minImageExtent.height) { + swapchainExtent.height = surfCapabilities.minImageExtent.height; + } else if (swapchainExtent.height > surfCapabilities.maxImageExtent.height) { + swapchainExtent.height = surfCapabilities.maxImageExtent.height; + } + } else { + // If the surface size is defined, the swap chain size must match + swapchainExtent = surfCapabilities.currentExtent; + window->width = surfCapabilities.currentExtent.width; + window->height = surfCapabilities.currentExtent.height; + } + + if (window->width == 0 || window->height == 0) { + free(presentModes); + //likely window minimized, no swapchain created + return OK; + } + // The FIFO present mode is guaranteed by the spec to be supported + // and to have no tearing. It's a great default present mode to use. + VkPresentModeKHR swapchainPresentMode = VK_PRESENT_MODE_FIFO_KHR; + + // There are times when you may wish to use another present mode. The + // following code shows how to select them, and the comments provide some + // reasons you may wish to use them. + // + // It should be noted that Vulkan 1.0 doesn't provide a method for + // synchronizing rendering with the presentation engine's display. There + // is a method provided for throttling rendering with the display, but + // there are some presentation engines for which this method will not work. + // If an application doesn't throttle its rendering, and if it renders much + // faster than the refresh rate of the display, this can waste power on + // mobile devices. That is because power is being spent rendering images + // that may never be seen. + + // VK_PRESENT_MODE_IMMEDIATE_KHR is for applications that don't care about + // tearing, or have some way of synchronizing their rendering with the + // display. + // VK_PRESENT_MODE_MAILBOX_KHR may be useful for applications that + // generally render a new presentable image every refresh cycle, but are + // occasionally early. In this case, the application wants the new image + // to be displayed instead of the previously-queued-for-presentation image + // that has not yet been displayed. + // VK_PRESENT_MODE_FIFO_RELAXED_KHR is for applications that generally + // render a new presentable image every refresh cycle, but are occasionally + // late. In this case (perhaps because of stuttering/latency concerns), + // the application wants the late image to be immediately displayed, even + // though that may mean some tearing. + + if (window->presentMode != swapchainPresentMode) { + for (size_t i = 0; i < presentModeCount; ++i) { + if (presentModes[i] == window->presentMode) { + swapchainPresentMode = window->presentMode; + break; + } + } + } + free(presentModes); + ERR_FAIL_COND_V_MSG(swapchainPresentMode != window->presentMode, ERR_CANT_CREATE, "Present mode specified is not supported\n"); + + // Determine the number of VkImages to use in the swap chain. + // Application desires to acquire 3 images at a time for triple + // buffering + uint32_t desiredNumOfSwapchainImages = 3; + if (desiredNumOfSwapchainImages < surfCapabilities.minImageCount) { + desiredNumOfSwapchainImages = surfCapabilities.minImageCount; + } + // If maxImageCount is 0, we can ask for as many images as we want; + // otherwise we're limited to maxImageCount + if ((surfCapabilities.maxImageCount > 0) && (desiredNumOfSwapchainImages > surfCapabilities.maxImageCount)) { + // Application must settle for fewer images than desired: + desiredNumOfSwapchainImages = surfCapabilities.maxImageCount; + } + + VkSurfaceTransformFlagsKHR preTransform; + if (surfCapabilities.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) { + preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; + } else { + preTransform = surfCapabilities.currentTransform; + } + + // Find a supported composite alpha mode - one of these is guaranteed to be set + VkCompositeAlphaFlagBitsKHR compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; + VkCompositeAlphaFlagBitsKHR compositeAlphaFlags[4] = { + VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR, + VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR, + VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR, + VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR, + }; + for (uint32_t i = 0; i < ARRAY_SIZE(compositeAlphaFlags); i++) { + if (surfCapabilities.supportedCompositeAlpha & compositeAlphaFlags[i]) { + compositeAlpha = compositeAlphaFlags[i]; + break; + } + } + + VkSwapchainCreateInfoKHR swapchain_ci = { + /*sType*/ VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, + /*pNext*/ NULL, + /*flags*/ 0, + /*surface*/ window->surface, + /*minImageCount*/ desiredNumOfSwapchainImages, + /*imageFormat*/ format, + /*imageColorSpace*/ color_space, + /*imageExtent*/ { + /*width*/ swapchainExtent.width, + /*height*/ swapchainExtent.height, + }, + /*imageArrayLayers*/ 1, + /*imageUsage*/ VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, + /*imageSharingMode*/ VK_SHARING_MODE_EXCLUSIVE, + /*queueFamilyIndexCount*/ 0, + /*pQueueFamilyIndices*/ NULL, + /*preTransform*/ (VkSurfaceTransformFlagBitsKHR)preTransform, + /*compositeAlpha*/ compositeAlpha, + /*presentMode*/ swapchainPresentMode, + /*clipped*/ true, + /*oldSwapchain*/ NULL, + }; + + err = fpCreateSwapchainKHR(device, &swapchain_ci, NULL, &window->swapchain); + ERR_FAIL_COND_V(err, ERR_CANT_CREATE); + + uint32_t sp_image_count; + err = fpGetSwapchainImagesKHR(device, window->swapchain, &sp_image_count, NULL); + ERR_FAIL_COND_V(err, ERR_CANT_CREATE); + + if (swapchainImageCount == 0) { + //assign here for the first time. + swapchainImageCount = sp_image_count; + } else { + ERR_FAIL_COND_V(swapchainImageCount != sp_image_count, ERR_BUG); + } + + VkImage *swapchainImages = (VkImage *)malloc(swapchainImageCount * sizeof(VkImage)); + ERR_FAIL_COND_V(!swapchainImages, ERR_CANT_CREATE); + err = fpGetSwapchainImagesKHR(device, window->swapchain, &swapchainImageCount, swapchainImages); + if (err) { + free(swapchainImages); + ERR_FAIL_V(ERR_CANT_CREATE); + } + + window->swapchain_image_resources = + (SwapchainImageResources *)malloc(sizeof(SwapchainImageResources) * swapchainImageCount); + if (!window->swapchain_image_resources) { + free(swapchainImages); + ERR_FAIL_V(ERR_CANT_CREATE); + } + + for (uint32_t i = 0; i < swapchainImageCount; i++) { + VkImageViewCreateInfo color_image_view = { + /*sType*/ VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, + /*pNext*/ NULL, + /*flags*/ 0, + /*image*/ swapchainImages[i], + /*viewType*/ VK_IMAGE_VIEW_TYPE_2D, + /*format*/ format, + /*components*/ { + /*r*/ VK_COMPONENT_SWIZZLE_R, + /*g*/ VK_COMPONENT_SWIZZLE_G, + /*b*/ VK_COMPONENT_SWIZZLE_B, + /*a*/ VK_COMPONENT_SWIZZLE_A, + }, + /*subresourceRange*/ { /*aspectMask*/ VK_IMAGE_ASPECT_COLOR_BIT, + /*baseMipLevel*/ 0, + /*levelCount*/ 1, + /*baseArrayLayer*/ 0, + /*layerCount*/ 1 }, + }; + + window->swapchain_image_resources[i].image = swapchainImages[i]; + + color_image_view.image = window->swapchain_image_resources[i].image; + + err = vkCreateImageView(device, &color_image_view, NULL, &window->swapchain_image_resources[i].view); + if (err) { + free(swapchainImages); + ERR_FAIL_V(ERR_CANT_CREATE); + } + } + + free(swapchainImages); + + /******** FRAMEBUFFER ************/ + + { + const VkAttachmentDescription attachment = { + + /*flags*/ 0, + /*format*/ format, + /*samples*/ VK_SAMPLE_COUNT_1_BIT, + /*loadOp*/ VK_ATTACHMENT_LOAD_OP_CLEAR, + /*storeOp*/ VK_ATTACHMENT_STORE_OP_STORE, + /*stencilLoadOp*/ VK_ATTACHMENT_LOAD_OP_DONT_CARE, + /*stencilStoreOp*/ VK_ATTACHMENT_STORE_OP_DONT_CARE, + /*initialLayout*/ VK_IMAGE_LAYOUT_UNDEFINED, + /*finalLayout*/ VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, + + }; + const VkAttachmentReference color_reference = { + /*attachment*/ 0, + /*layout*/ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + }; + + const VkSubpassDescription subpass = { + /*flags*/ 0, + /*pipelineBindPoint*/ VK_PIPELINE_BIND_POINT_GRAPHICS, + /*inputAttachmentCount*/ 0, + /*pInputAttachments*/ NULL, + /*colorAttachmentCount*/ 1, + /*pColorAttachments*/ &color_reference, + /*pResolveAttachments*/ NULL, + /*pDepthStencilAttachment*/ NULL, + /*preserveAttachmentCount*/ 0, + /*pPreserveAttachments*/ NULL, + }; + const VkRenderPassCreateInfo rp_info = { + /*sTyp*/ VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, + /*pNext*/ NULL, + /*flags*/ 0, + /*attachmentCount*/ 1, + /*pAttachments*/ &attachment, + /*subpassCount*/ 1, + /*pSubpasses*/ &subpass, + /*dependencyCount*/ 0, + /*pDependencies*/ NULL, + }; + + err = vkCreateRenderPass(device, &rp_info, NULL, &window->render_pass); + ERR_FAIL_COND_V(err, ERR_CANT_CREATE); + + for (uint32_t i = 0; i < swapchainImageCount; i++) { + const VkFramebufferCreateInfo fb_info = { + /*sType*/ VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, + /*pNext*/ NULL, + /*flags*/ 0, + /*renderPass*/ window->render_pass, + /*attachmentCount*/ 1, + /*pAttachments*/ &window->swapchain_image_resources[i].view, + /*width*/ (uint32_t)window->width, + /*height*/ (uint32_t)window->height, + /*layers*/ 1, + }; + + err = vkCreateFramebuffer(device, &fb_info, NULL, &window->swapchain_image_resources[i].framebuffer); + ERR_FAIL_COND_V(err, ERR_CANT_CREATE); + } + } + + /******** SEPARATE PRESENT QUEUE ************/ + + if (separate_present_queue) { + const VkCommandPoolCreateInfo present_cmd_pool_info = { + /*sType*/ VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, + /*pNext*/ NULL, + /*flags*/ 0, + /*queueFamilyIndex*/ present_queue_family_index, + }; + err = vkCreateCommandPool(device, &present_cmd_pool_info, NULL, &window->present_cmd_pool); + ERR_FAIL_COND_V(err, ERR_CANT_CREATE); + const VkCommandBufferAllocateInfo present_cmd_info = { + /*sType*/ VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, + /*pNext*/ NULL, + /*commandPool*/ window->present_cmd_pool, + /*level*/ VK_COMMAND_BUFFER_LEVEL_PRIMARY, + /*commandBufferCount*/ 1, + }; + for (uint32_t i = 0; i < swapchainImageCount; i++) { + err = vkAllocateCommandBuffers(device, &present_cmd_info, + &window->swapchain_image_resources[i].graphics_to_present_cmd); + ERR_FAIL_COND_V(err, ERR_CANT_CREATE); + + const VkCommandBufferBeginInfo cmd_buf_info = { + /*sType*/ VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, + /*pNext*/ NULL, + /*flags*/ VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT, + /*pInheritanceInfo*/ NULL, + }; + err = vkBeginCommandBuffer(window->swapchain_image_resources[i].graphics_to_present_cmd, &cmd_buf_info); + ERR_FAIL_COND_V(err, ERR_CANT_CREATE); + + VkImageMemoryBarrier image_ownership_barrier = { + /*sType*/ VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, + /*pNext*/ NULL, + /*srcAccessMask*/ 0, + /*dstAccessMask*/ VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, + /*oldLayout*/ VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, + /*newLayout*/ VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, + /*srcQueueFamilyIndex*/ graphics_queue_family_index, + /*dstQueueFamilyIndex*/ present_queue_family_index, + /*image*/ window->swapchain_image_resources[i].image, + /*subresourceRange*/ { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 } + }; + + vkCmdPipelineBarrier(window->swapchain_image_resources[i].graphics_to_present_cmd, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0, 0, NULL, 0, NULL, 1, &image_ownership_barrier); + err = vkEndCommandBuffer(window->swapchain_image_resources[i].graphics_to_present_cmd); + ERR_FAIL_COND_V(err, ERR_CANT_CREATE); + } + } + + //reset current buffer + window->current_buffer = 0; + + return OK; +} + +Error VulkanContext::initialize() { + + Error err = _create_physical_device(); + if (err) { + return err; + } + print_line("Vulkan physical device creation success o_O"); + return OK; +} + +void VulkanContext::set_setup_buffer(const VkCommandBuffer &pCommandBuffer) { + command_buffer_queue.write[0] = pCommandBuffer; +} + +void VulkanContext::append_command_buffer(const VkCommandBuffer &pCommandBuffer) { + + if (command_buffer_queue.size() <= command_buffer_count) { + command_buffer_queue.resize(command_buffer_count + 1); + } + + command_buffer_queue.write[command_buffer_count] = pCommandBuffer; + command_buffer_count++; +} + +void VulkanContext::flush(bool p_flush_setup, bool p_flush_pending) { + + // ensure everything else pending is executed + vkDeviceWaitIdle(device); + + //flush the pending setup buffer + + if (p_flush_setup && command_buffer_queue[0]) { + + //use a fence to wait for everything done + VkSubmitInfo submit_info; + submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submit_info.pNext = NULL; + submit_info.pWaitDstStageMask = NULL; + submit_info.waitSemaphoreCount = 0; + submit_info.pWaitSemaphores = NULL; + submit_info.commandBufferCount = 1; + submit_info.pCommandBuffers = command_buffer_queue.ptr(); + submit_info.signalSemaphoreCount = 0; + submit_info.pSignalSemaphores = NULL; + VkResult err = vkQueueSubmit(graphics_queue, 1, &submit_info, VK_NULL_HANDLE); + command_buffer_queue.write[0] = NULL; + ERR_FAIL_COND(err); + vkDeviceWaitIdle(device); + } + + if (p_flush_pending && command_buffer_count > 1) { + + //use a fence to wait for everything done + + VkSubmitInfo submit_info; + submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submit_info.pNext = NULL; + submit_info.pWaitDstStageMask = NULL; + submit_info.waitSemaphoreCount = 0; + submit_info.pWaitSemaphores = NULL; + submit_info.commandBufferCount = command_buffer_count - 1; + submit_info.pCommandBuffers = command_buffer_queue.ptr() + 1; + submit_info.signalSemaphoreCount = 0; + submit_info.pSignalSemaphores = NULL; + VkResult err = vkQueueSubmit(graphics_queue, 1, &submit_info, VK_NULL_HANDLE); + ERR_FAIL_COND(err); + vkDeviceWaitIdle(device); + + command_buffer_count = 1; + } +} + +Error VulkanContext::prepare_buffers() { + + if (!queues_initialized) { + return OK; + } + + VkResult err; + + // Ensure no more than FRAME_LAG renderings are outstanding + vkWaitForFences(device, 1, &fences[frame_index], VK_TRUE, UINT64_MAX); + vkResetFences(device, 1, &fences[frame_index]); + + for (Map<int, Window>::Element *E = windows.front(); E; E = E->next()) { + + Window *w = &E->get(); + + if (w->swapchain == VK_NULL_HANDLE) { + continue; + } + + do { + // Get the index of the next available swapchain image: + err = + fpAcquireNextImageKHR(device, w->swapchain, UINT64_MAX, + image_acquired_semaphores[frame_index], VK_NULL_HANDLE, &w->current_buffer); + + if (err == VK_ERROR_OUT_OF_DATE_KHR) { + // swapchain is out of date (e.g. the window was resized) and + // must be recreated: + print_line("early out of data"); + //resize_notify(); + _update_swap_chain(w); + } else if (err == VK_SUBOPTIMAL_KHR) { + print_line("early suboptimal"); + // swapchain is not as optimal as it could be, but the platform's + // presentation engine will still present the image correctly. + break; + } else { + ERR_FAIL_COND_V(err, ERR_CANT_CREATE); + } + } while (err != VK_SUCCESS); + } + + buffers_prepared = true; + + return OK; +} + +Error VulkanContext::swap_buffers() { + + if (!queues_initialized) { + return OK; + } + + // print_line("swapbuffers?"); + VkResult err; + +#if 0 + if (VK_GOOGLE_display_timing_enabled) { + // Look at what happened to previous presents, and make appropriate + // adjustments in timing: + DemoUpdateTargetIPD(demo); + + // Note: a real application would position its geometry to that it's in + // the correct locatoin for when the next image is presented. It might + // also wait, so that there's less latency between any input and when + // the next image is rendered/presented. This demo program is so + // simple that it doesn't do either of those. + } +#endif + // Wait for the image acquired semaphore to be signaled to ensure + // that the image won't be rendered to until the presentation + // engine has fully released ownership to the application, and it is + // okay to render to the image. + + const VkCommandBuffer *commands_ptr = NULL; + uint32_t commands_to_submit = 0; + + if (command_buffer_queue[0] == NULL) { + //no setup command, but commands to submit, submit from the first and skip command + if (command_buffer_count > 1) { + commands_ptr = command_buffer_queue.ptr() + 1; + commands_to_submit = command_buffer_count - 1; + } + } else { + commands_ptr = command_buffer_queue.ptr(); + commands_to_submit = command_buffer_count; + } + + VkPipelineStageFlags pipe_stage_flags; + VkSubmitInfo submit_info; + submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submit_info.pNext = NULL; + submit_info.pWaitDstStageMask = &pipe_stage_flags; + pipe_stage_flags = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + submit_info.waitSemaphoreCount = 1; + submit_info.pWaitSemaphores = &image_acquired_semaphores[frame_index]; + submit_info.commandBufferCount = commands_to_submit; + submit_info.pCommandBuffers = commands_ptr; + submit_info.signalSemaphoreCount = 1; + submit_info.pSignalSemaphores = &draw_complete_semaphores[frame_index]; + err = vkQueueSubmit(graphics_queue, 1, &submit_info, fences[frame_index]); + ERR_FAIL_COND_V(err, ERR_CANT_CREATE); + + command_buffer_queue.write[0] = NULL; + command_buffer_count = 1; + + if (separate_present_queue) { + // If we are using separate queues, change image ownership to the + // present queue before presenting, waiting for the draw complete + // semaphore and signalling the ownership released semaphore when finished + VkFence nullFence = VK_NULL_HANDLE; + pipe_stage_flags = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + submit_info.waitSemaphoreCount = 1; + submit_info.pWaitSemaphores = &draw_complete_semaphores[frame_index]; + submit_info.commandBufferCount = 0; + + VkCommandBuffer *cmdbufptr = (VkCommandBuffer *)alloca(sizeof(VkCommandBuffer *) * windows.size()); + submit_info.pCommandBuffers = cmdbufptr; + + for (Map<int, Window>::Element *E = windows.front(); E; E = E->next()) { + Window *w = &E->get(); + + if (w->swapchain == VK_NULL_HANDLE) { + continue; + } + cmdbufptr[submit_info.commandBufferCount] = w->swapchain_image_resources[w->current_buffer].graphics_to_present_cmd; + submit_info.commandBufferCount++; + } + + submit_info.signalSemaphoreCount = 1; + submit_info.pSignalSemaphores = &image_ownership_semaphores[frame_index]; + err = vkQueueSubmit(present_queue, 1, &submit_info, nullFence); + ERR_FAIL_COND_V(err, ERR_CANT_CREATE); + } + + // If we are using separate queues we have to wait for image ownership, + // otherwise wait for draw complete + VkPresentInfoKHR present = { + /*sType*/ VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, + /*pNext*/ NULL, + /*waitSemaphoreCount*/ 1, + /*pWaitSemaphores*/ (separate_present_queue) ? &image_ownership_semaphores[frame_index] : &draw_complete_semaphores[frame_index], + /*swapchainCount*/ 0, + /*pSwapchain*/ NULL, + /*pImageIndices*/ NULL, + /*pResults*/ NULL, + }; + + VkSwapchainKHR *pSwapchains = (VkSwapchainKHR *)alloca(sizeof(VkSwapchainKHR *) * windows.size()); + uint32_t *pImageIndices = (uint32_t *)alloca(sizeof(uint32_t *) * windows.size()); + + present.pSwapchains = pSwapchains; + present.pImageIndices = pImageIndices; + + for (Map<int, Window>::Element *E = windows.front(); E; E = E->next()) { + Window *w = &E->get(); + + if (w->swapchain == VK_NULL_HANDLE) { + continue; + } + pSwapchains[present.swapchainCount] = w->swapchain; + pImageIndices[present.swapchainCount] = w->current_buffer; + present.swapchainCount++; + } + +#if 0 + if (VK_KHR_incremental_present_enabled) { + // If using VK_KHR_incremental_present, we provide a hint of the region + // that contains changed content relative to the previously-presented + // image. The implementation can use this hint in order to save + // work/power (by only copying the region in the hint). The + // implementation is free to ignore the hint though, and so we must + // ensure that the entire image has the correctly-drawn content. + uint32_t eighthOfWidth = width / 8; + uint32_t eighthOfHeight = height / 8; + VkRectLayerKHR rect = { + /*offset.x*/ eighthOfWidth, + /*offset.y*/ eighthOfHeight, + /*extent.width*/ eighthOfWidth * 6, + /*extent.height*/ eighthOfHeight * 6, + /*layer*/ 0, + }; + VkPresentRegionKHR region = { + /*rectangleCount*/ 1, + /*pRectangles*/ &rect, + }; + VkPresentRegionsKHR regions = { + /*sType*/ VK_STRUCTURE_TYPE_PRESENT_REGIONS_KHR, + /*pNext*/ present.pNext, + /*swapchainCount*/ present.swapchainCount, + /*pRegions*/ ®ion, + }; + present.pNext = ®ions; + } +#endif + +#if 0 + if (VK_GOOGLE_display_timing_enabled) { + VkPresentTimeGOOGLE ptime; + if (prev_desired_present_time == 0) { + // This must be the first present for this swapchain. + // + // We don't know where we are relative to the presentation engine's + // display's refresh cycle. We also don't know how long rendering + // takes. Let's make a grossly-simplified assumption that the + // desiredPresentTime should be half way between now and + // now+target_IPD. We will adjust over time. + uint64_t curtime = getTimeInNanoseconds(); + if (curtime == 0) { + // Since we didn't find out the current time, don't give a + // desiredPresentTime: + ptime.desiredPresentTime = 0; + } else { + ptime.desiredPresentTime = curtime + (target_IPD >> 1); + } + } else { + ptime.desiredPresentTime = (prev_desired_present_time + target_IPD); + } + ptime.presentID = next_present_id++; + prev_desired_present_time = ptime.desiredPresentTime; + + VkPresentTimesInfoGOOGLE present_time = { + /*sType*/ VK_STRUCTURE_TYPE_PRESENT_TIMES_INFO_GOOGLE, + /*pNext*/ present.pNext, + /*swapchainCount*/ present.swapchainCount, + /*pTimes*/ &ptime, + }; + if (VK_GOOGLE_display_timing_enabled) { + present.pNext = &present_time; + } + } +#endif + static int total_frames = 0; + total_frames++; + // print_line("current buffer: " + itos(current_buffer)); + err = fpQueuePresentKHR(present_queue, &present); + + frame_index += 1; + frame_index %= FRAME_LAG; + + if (err == VK_ERROR_OUT_OF_DATE_KHR) { + // swapchain is out of date (e.g. the window was resized) and + // must be recreated: + print_line("out of date"); + resize_notify(); + } else if (err == VK_SUBOPTIMAL_KHR) { + // swapchain is not as optimal as it could be, but the platform's + // presentation engine will still present the image correctly. + print_line("suboptimal"); + } else { + ERR_FAIL_COND_V(err, ERR_CANT_CREATE); + } + + buffers_prepared = false; + return OK; +} + +void VulkanContext::resize_notify() { +} + +VkDevice VulkanContext::get_device() { + return device; +} + +VkPhysicalDevice VulkanContext::get_physical_device() { + return gpu; +} +int VulkanContext::get_swapchain_image_count() const { + return swapchainImageCount; +} +uint32_t VulkanContext::get_graphics_queue() const { + return graphics_queue_family_index; +} + +VkFormat VulkanContext::get_screen_format() const { + return format; +} + +VkPhysicalDeviceLimits VulkanContext::get_device_limits() const { + return gpu_props.limits; +} + +VulkanContext::VulkanContext() { + command_buffer_count = 0; + instance_validation_layers = NULL; + use_validation_layers = true; + VK_KHR_incremental_present_enabled = true; + VK_GOOGLE_display_timing_enabled = true; + + command_buffer_queue.resize(1); //first one is the setup command always + command_buffer_queue.write[0] = NULL; + command_buffer_count = 1; + queues_initialized = false; + + buffers_prepared = false; + swapchainImageCount = 0; + last_window_id = 0; +} + +VulkanContext::~VulkanContext() { + if (queue_props) { + free(queue_props); + } +} diff --git a/drivers/vulkan/vulkan_context.h b/drivers/vulkan/vulkan_context.h new file mode 100644 index 0000000000..458cb6d793 --- /dev/null +++ b/drivers/vulkan/vulkan_context.h @@ -0,0 +1,212 @@ +/*************************************************************************/ +/* vulkan_context.h */ +/*************************************************************************/ +/* 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. */ +/*************************************************************************/ + +#ifndef VULKAN_CONTEXT_H +#define VULKAN_CONTEXT_H + +#include "core/error_list.h" +#include "core/map.h" +#include "core/ustring.h" +#include <vulkan/vulkan.h> + +class VulkanContext { + + enum { + MAX_EXTENSIONS = 128, + MAX_LAYERS = 64, + FRAME_LAG = 2 + }; + + bool use_validation_layers; + + VkInstance inst; + VkSurfaceKHR surface; + VkPhysicalDevice gpu; + VkPhysicalDeviceProperties gpu_props; + uint32_t queue_family_count; + VkQueueFamilyProperties *queue_props; + VkDevice device; + + //present + bool queues_initialized; + uint32_t graphics_queue_family_index; + uint32_t present_queue_family_index; + bool separate_present_queue; + VkQueue graphics_queue; + VkQueue present_queue; + VkColorSpaceKHR color_space; + VkFormat format; + VkSemaphore image_acquired_semaphores[FRAME_LAG]; + VkSemaphore draw_complete_semaphores[FRAME_LAG]; + VkSemaphore image_ownership_semaphores[FRAME_LAG]; + int frame_index; + VkFence fences[FRAME_LAG]; + VkPhysicalDeviceMemoryProperties memory_properties; + VkPhysicalDeviceFeatures physical_device_features; + + typedef struct { + VkImage image; + VkCommandBuffer graphics_to_present_cmd; + VkImageView view; + VkFramebuffer framebuffer; + + } SwapchainImageResources; + + struct Window { + + bool is_minimzed; + VkSurfaceKHR surface; + VkSwapchainKHR swapchain; + SwapchainImageResources *swapchain_image_resources; + VkPresentModeKHR presentMode; + uint32_t current_buffer; + int width; + int height; + VkCommandPool present_cmd_pool; //for separate present queue + + VkRenderPass render_pass; + + Window() { + width = 0; + height = 0; + render_pass = VK_NULL_HANDLE; + current_buffer = 0; + surface = VK_NULL_HANDLE; + swapchain_image_resources = VK_NULL_HANDLE; + swapchain = VK_NULL_HANDLE; + is_minimzed = false; + presentMode = VK_PRESENT_MODE_FIFO_KHR; + } + }; + + Map<int, Window> windows; + int last_window_id; + uint32_t swapchainImageCount; + + //commands + + bool prepared; + + //extensions + bool VK_KHR_incremental_present_enabled; + bool VK_GOOGLE_display_timing_enabled; + const char **instance_validation_layers; + uint32_t enabled_extension_count; + uint32_t enabled_layer_count; + const char *extension_names[MAX_EXTENSIONS]; + const char *enabled_layers[MAX_LAYERS]; + + PFN_vkCreateDebugUtilsMessengerEXT CreateDebugUtilsMessengerEXT; + PFN_vkDestroyDebugUtilsMessengerEXT DestroyDebugUtilsMessengerEXT; + PFN_vkSubmitDebugUtilsMessageEXT SubmitDebugUtilsMessageEXT; + PFN_vkCmdBeginDebugUtilsLabelEXT CmdBeginDebugUtilsLabelEXT; + PFN_vkCmdEndDebugUtilsLabelEXT CmdEndDebugUtilsLabelEXT; + PFN_vkCmdInsertDebugUtilsLabelEXT CmdInsertDebugUtilsLabelEXT; + PFN_vkSetDebugUtilsObjectNameEXT SetDebugUtilsObjectNameEXT; + PFN_vkGetPhysicalDeviceSurfaceSupportKHR fpGetPhysicalDeviceSurfaceSupportKHR; + PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR fpGetPhysicalDeviceSurfaceCapabilitiesKHR; + PFN_vkGetPhysicalDeviceSurfaceFormatsKHR fpGetPhysicalDeviceSurfaceFormatsKHR; + PFN_vkGetPhysicalDeviceSurfacePresentModesKHR fpGetPhysicalDeviceSurfacePresentModesKHR; + PFN_vkCreateSwapchainKHR fpCreateSwapchainKHR; + PFN_vkDestroySwapchainKHR fpDestroySwapchainKHR; + PFN_vkGetSwapchainImagesKHR fpGetSwapchainImagesKHR; + PFN_vkAcquireNextImageKHR fpAcquireNextImageKHR; + PFN_vkQueuePresentKHR fpQueuePresentKHR; + PFN_vkGetRefreshCycleDurationGOOGLE fpGetRefreshCycleDurationGOOGLE; + PFN_vkGetPastPresentationTimingGOOGLE fpGetPastPresentationTimingGOOGLE; + + VkDebugUtilsMessengerEXT dbg_messenger; + + Error _create_validation_layers(); + Error _initialize_extensions(); + + VkBool32 _check_layers(uint32_t check_count, const char **check_names, uint32_t layer_count, VkLayerProperties *layers); + static VKAPI_ATTR VkBool32 VKAPI_CALL _debug_messenger_callback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, + VkDebugUtilsMessageTypeFlagsEXT messageType, + const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData, + void *pUserData); + + Error _create_physical_device(); + + Error _initialize_queues(VkSurfaceKHR surface); + + Error _create_device(); + + Error _clean_up_swap_chain(Window *window); + + Error _update_swap_chain(Window *window); + + Error _create_swap_chain(); + Error _create_semaphores(); + + Vector<VkCommandBuffer> command_buffer_queue; + int command_buffer_count; + +protected: + virtual const char *_get_platform_surface_extension() const = 0; + // virtual VkResult _create_surface(VkSurfaceKHR *surface, VkInstance p_instance) = 0; + + virtual int _window_create(VkSurfaceKHR p_surface, int p_width, int p_height); + + VkInstance _get_instance() { + return inst; + } + + bool buffers_prepared; + +public: + VkDevice get_device(); + VkPhysicalDevice get_physical_device(); + int get_swapchain_image_count() const; + uint32_t get_graphics_queue() const; + + void window_resize(int p_window_id, int p_width, int p_height); + int window_get_width(int p_window = 0); + int window_get_height(int p_window = 0); + void window_destroy(int p_window_id); + VkFramebuffer window_get_framebuffer(int p_window = 0); + VkRenderPass window_get_render_pass(int p_window = 0); + + VkFormat get_screen_format() const; + VkPhysicalDeviceLimits get_device_limits() const; + + void set_setup_buffer(const VkCommandBuffer &pCommandBuffer); + void append_command_buffer(const VkCommandBuffer &pCommandBuffer); + void resize_notify(); + void flush(bool p_flush_setup = false, bool p_flush_pending = false); + Error prepare_buffers(); + Error swap_buffers(); + Error initialize(); + + VulkanContext(); + virtual ~VulkanContext(); +}; + +#endif // VULKAN_DEVICE_H diff --git a/drivers/wasapi/audio_driver_wasapi.cpp b/drivers/wasapi/audio_driver_wasapi.cpp index 9a05284aea..8aa6fb96c9 100644 --- a/drivers/wasapi/audio_driver_wasapi.cpp +++ b/drivers/wasapi/audio_driver_wasapi.cpp @@ -327,7 +327,7 @@ Error AudioDriverWASAPI::init_render_device(bool reinit) { break; default: - WARN_PRINTS("WASAPI: Unsupported number of channels: " + itos(audio_output.channels)); + WARN_PRINT("WASAPI: Unsupported number of channels: " + itos(audio_output.channels)); channels = 2; break; } diff --git a/drivers/windows/file_access_windows.cpp b/drivers/windows/file_access_windows.cpp index 1b8760fdc7..01d2b8716f 100644 --- a/drivers/windows/file_access_windows.cpp +++ b/drivers/windows/file_access_windows.cpp @@ -102,7 +102,7 @@ Error FileAccessWindows::_open(const String &p_path, int p_mode_flags) { String base_file = path.get_file(); if (base_file != fname && base_file.findn(fname) == 0) { - WARN_PRINTS("Case mismatch opening requested file '" + base_file + "', stored as '" + fname + "' in the filesystem. This file will not open when exported to other case-sensitive platforms."); + WARN_PRINT("Case mismatch opening requested file '" + base_file + "', stored as '" + fname + "' in the filesystem. This file will not open when exported to other case-sensitive platforms."); } } FindClose(f); diff --git a/drivers/windows/semaphore_windows.cpp b/drivers/windows/semaphore_windows.cpp index ea8032ffe2..1b53e311ff 100644 --- a/drivers/windows/semaphore_windows.cpp +++ b/drivers/windows/semaphore_windows.cpp @@ -61,7 +61,7 @@ int SemaphoreWindows::get() const { ERR_FAIL_V(-1); } -Semaphore *SemaphoreWindows::create_semaphore_windows() { +SemaphoreOld *SemaphoreWindows::create_semaphore_windows() { return memnew(SemaphoreWindows); } diff --git a/drivers/windows/semaphore_windows.h b/drivers/windows/semaphore_windows.h index 01712b6778..159e8b3b96 100644 --- a/drivers/windows/semaphore_windows.h +++ b/drivers/windows/semaphore_windows.h @@ -37,11 +37,11 @@ #include <windows.h> -class SemaphoreWindows : public Semaphore { +class SemaphoreWindows : public SemaphoreOld { mutable HANDLE semaphore; - static Semaphore *create_semaphore_windows(); + static SemaphoreOld *create_semaphore_windows(); public: virtual Error wait(); diff --git a/drivers/winmidi/midi_driver_winmidi.cpp b/drivers/winmidi/midi_driver_winmidi.cpp index e79216efaf..01c194b7d8 100644 --- a/drivers/winmidi/midi_driver_winmidi.cpp +++ b/drivers/winmidi/midi_driver_winmidi.cpp @@ -53,12 +53,12 @@ Error MIDIDriverWinMidi::open() { } else { char err[256]; midiInGetErrorText(res, err, 256); - ERR_PRINTS("midiInOpen error: " + String(err)); + ERR_PRINT("midiInOpen error: " + String(err)); MIDIINCAPS caps; res = midiInGetDevCaps(i, &caps, sizeof(MIDIINCAPS)); if (res == MMSYSERR_NOERROR) { - ERR_PRINTS("Can't open MIDI device \"" + String(caps.szPname) + "\", is it being used by another application?"); + ERR_PRINT("Can't open MIDI device \"" + String(caps.szPname) + "\", is it being used by another application?"); } } } |