Path: blob/master/servers/rendering/rendering_device.cpp
10277 views
/**************************************************************************/1/* rendering_device.cpp */2/**************************************************************************/3/* This file is part of: */4/* GODOT ENGINE */5/* https://godotengine.org */6/**************************************************************************/7/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */8/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */9/* */10/* Permission is hereby granted, free of charge, to any person obtaining */11/* a copy of this software and associated documentation files (the */12/* "Software"), to deal in the Software without restriction, including */13/* without limitation the rights to use, copy, modify, merge, publish, */14/* distribute, sublicense, and/or sell copies of the Software, and to */15/* permit persons to whom the Software is furnished to do so, subject to */16/* the following conditions: */17/* */18/* The above copyright notice and this permission notice shall be */19/* included in all copies or substantial portions of the Software. */20/* */21/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */22/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */23/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */24/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */25/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */26/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */27/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */28/**************************************************************************/2930#include "rendering_device.h"31#include "rendering_device.compat.inc"3233#include "rendering_device_binds.h"34#include "shader_include_db.h"3536#include "core/config/project_settings.h"37#include "core/io/dir_access.h"38#include "modules/modules_enabled.gen.h"3940#ifdef MODULE_GLSLANG_ENABLED41#include "modules/glslang/shader_compile.h"42#endif4344#define FORCE_SEPARATE_PRESENT_QUEUE 045#define PRINT_FRAMEBUFFER_FORMAT 04647#define ERR_RENDER_THREAD_MSG String("This function (") + String(__func__) + String(") can only be called from the render thread. ")48#define ERR_RENDER_THREAD_GUARD() ERR_FAIL_COND_MSG(render_thread_id != Thread::get_caller_id(), ERR_RENDER_THREAD_MSG);49#define ERR_RENDER_THREAD_GUARD_V(m_ret) ERR_FAIL_COND_V_MSG(render_thread_id != Thread::get_caller_id(), (m_ret), ERR_RENDER_THREAD_MSG);5051/**************************/52/**** HELPER FUNCTIONS ****/53/**************************/5455static String _get_device_vendor_name(const RenderingContextDriver::Device &p_device) {56switch (p_device.vendor) {57case RenderingContextDriver::Vendor::VENDOR_AMD:58return "AMD";59case RenderingContextDriver::Vendor::VENDOR_IMGTEC:60return "ImgTec";61case RenderingContextDriver::Vendor::VENDOR_APPLE:62return "Apple";63case RenderingContextDriver::Vendor::VENDOR_NVIDIA:64return "NVIDIA";65case RenderingContextDriver::Vendor::VENDOR_ARM:66return "ARM";67case RenderingContextDriver::Vendor::VENDOR_MICROSOFT:68return "Microsoft";69case RenderingContextDriver::Vendor::VENDOR_QUALCOMM:70return "Qualcomm";71case RenderingContextDriver::Vendor::VENDOR_INTEL:72return "Intel";73default:74return "Unknown";75}76}7778static String _get_device_type_name(const RenderingContextDriver::Device &p_device) {79switch (p_device.type) {80case RenderingContextDriver::DEVICE_TYPE_INTEGRATED_GPU:81return "Integrated";82case RenderingContextDriver::DEVICE_TYPE_DISCRETE_GPU:83return "Discrete";84case RenderingContextDriver::DEVICE_TYPE_VIRTUAL_GPU:85return "Virtual";86case RenderingContextDriver::DEVICE_TYPE_CPU:87return "CPU";88case RenderingContextDriver::DEVICE_TYPE_OTHER:89default:90return "Other";91}92}9394static uint32_t _get_device_type_score(const RenderingContextDriver::Device &p_device) {95static const bool prefer_integrated = OS::get_singleton()->get_user_prefers_integrated_gpu();96switch (p_device.type) {97case RenderingContextDriver::DEVICE_TYPE_INTEGRATED_GPU:98return prefer_integrated ? 5 : 4;99case RenderingContextDriver::DEVICE_TYPE_DISCRETE_GPU:100return prefer_integrated ? 4 : 5;101case RenderingContextDriver::DEVICE_TYPE_VIRTUAL_GPU:102return 3;103case RenderingContextDriver::DEVICE_TYPE_CPU:104return 2;105case RenderingContextDriver::DEVICE_TYPE_OTHER:106default:107return 1;108}109}110111/**************************/112/**** RENDERING DEVICE ****/113/**************************/114115// When true, the command graph will attempt to reorder the rendering commands submitted by the user based on the dependencies detected from116// the commands automatically. This should improve rendering performance in most scenarios at the cost of some extra CPU overhead.117//118// This behavior can be disabled if it's suspected that the graph is not detecting dependencies correctly and more control over the order of119// the commands is desired (e.g. debugging).120121#define RENDER_GRAPH_REORDER 1122123// Synchronization barriers are issued between the graph's levels only with the necessary amount of detail to achieve the correct result. If124// it's suspected that the graph is not doing this correctly, full barriers can be issued instead that will block all types of operations125// between the synchronization levels. This setting will have a very negative impact on performance when enabled, so it's only intended for126// debugging purposes.127128#define RENDER_GRAPH_FULL_BARRIERS 0129130// The command graph can automatically issue secondary command buffers and record them on background threads when they reach an arbitrary131// size threshold. This can be very beneficial towards reducing the time the main thread takes to record all the rendering commands. However,132// this setting is not enabled by default as it's been shown to cause some strange issues with certain IHVs that have yet to be understood.133134#define SECONDARY_COMMAND_BUFFERS_PER_FRAME 0135136RenderingDevice *RenderingDevice::singleton = nullptr;137138RenderingDevice *RenderingDevice::get_singleton() {139return singleton;140}141142/***************************/143/**** ID INFRASTRUCTURE ****/144/***************************/145146void RenderingDevice::_add_dependency(RID p_id, RID p_depends_on) {147_THREAD_SAFE_METHOD_148149HashSet<RID> *set = dependency_map.getptr(p_depends_on);150if (set == nullptr) {151set = &dependency_map.insert(p_depends_on, HashSet<RID>())->value;152}153set->insert(p_id);154155set = reverse_dependency_map.getptr(p_id);156if (set == nullptr) {157set = &reverse_dependency_map.insert(p_id, HashSet<RID>())->value;158}159set->insert(p_depends_on);160}161162void RenderingDevice::_free_dependencies(RID p_id) {163_THREAD_SAFE_METHOD_164165// Direct dependencies must be freed.166167HashMap<RID, HashSet<RID>>::Iterator E = dependency_map.find(p_id);168if (E) {169while (E->value.size()) {170free(*E->value.begin());171}172dependency_map.remove(E);173}174175// Reverse dependencies must be unreferenced.176E = reverse_dependency_map.find(p_id);177178if (E) {179for (const RID &F : E->value) {180HashMap<RID, HashSet<RID>>::Iterator G = dependency_map.find(F);181ERR_CONTINUE(!G);182ERR_CONTINUE(!G->value.has(p_id));183G->value.erase(p_id);184}185186reverse_dependency_map.remove(E);187}188}189190/*******************************/191/**** SHADER INFRASTRUCTURE ****/192/*******************************/193194Vector<uint8_t> RenderingDevice::shader_compile_spirv_from_source(ShaderStage p_stage, const String &p_source_code, ShaderLanguage p_language, String *r_error, bool p_allow_cache) {195switch (p_language) {196#ifdef MODULE_GLSLANG_ENABLED197case ShaderLanguage::SHADER_LANGUAGE_GLSL: {198ShaderLanguageVersion language_version = driver->get_shader_container_format().get_shader_language_version();199ShaderSpirvVersion spirv_version = driver->get_shader_container_format().get_shader_spirv_version();200return compile_glslang_shader(p_stage, ShaderIncludeDB::parse_include_files(p_source_code), language_version, spirv_version, r_error);201}202#endif203default:204ERR_FAIL_V_MSG(Vector<uint8_t>(), "Shader language is not supported.");205}206}207208RID RenderingDevice::shader_create_from_spirv(const Vector<ShaderStageSPIRVData> &p_spirv, const String &p_shader_name) {209Vector<uint8_t> bytecode = shader_compile_binary_from_spirv(p_spirv, p_shader_name);210ERR_FAIL_COND_V(bytecode.is_empty(), RID());211return shader_create_from_bytecode(bytecode);212}213214/***************************/215/**** BUFFER MANAGEMENT ****/216/***************************/217218RenderingDevice::Buffer *RenderingDevice::_get_buffer_from_owner(RID p_buffer) {219Buffer *buffer = nullptr;220if (vertex_buffer_owner.owns(p_buffer)) {221buffer = vertex_buffer_owner.get_or_null(p_buffer);222} else if (index_buffer_owner.owns(p_buffer)) {223buffer = index_buffer_owner.get_or_null(p_buffer);224} else if (uniform_buffer_owner.owns(p_buffer)) {225buffer = uniform_buffer_owner.get_or_null(p_buffer);226} else if (texture_buffer_owner.owns(p_buffer)) {227DEV_ASSERT(false && "FIXME: Broken.");228//buffer = texture_buffer_owner.get_or_null(p_buffer)->buffer;229} else if (storage_buffer_owner.owns(p_buffer)) {230buffer = storage_buffer_owner.get_or_null(p_buffer);231}232return buffer;233}234235Error RenderingDevice::_buffer_initialize(Buffer *p_buffer, Span<uint8_t> p_data, uint32_t p_required_align) {236uint32_t transfer_worker_offset;237TransferWorker *transfer_worker = _acquire_transfer_worker(p_data.size(), p_required_align, transfer_worker_offset);238p_buffer->transfer_worker_index = transfer_worker->index;239240{241MutexLock lock(transfer_worker->operations_mutex);242p_buffer->transfer_worker_operation = ++transfer_worker->operations_counter;243}244245// Copy to the worker's staging buffer.246uint8_t *data_ptr = driver->buffer_map(transfer_worker->staging_buffer);247ERR_FAIL_NULL_V(data_ptr, ERR_CANT_CREATE);248249memcpy(data_ptr + transfer_worker_offset, p_data.ptr(), p_data.size());250driver->buffer_unmap(transfer_worker->staging_buffer);251252// Copy from the staging buffer to the real buffer.253RDD::BufferCopyRegion region;254region.src_offset = transfer_worker_offset;255region.dst_offset = 0;256region.size = p_data.size();257driver->command_copy_buffer(transfer_worker->command_buffer, transfer_worker->staging_buffer, p_buffer->driver_id, region);258259_release_transfer_worker(transfer_worker);260261return OK;262}263264Error RenderingDevice::_insert_staging_block(StagingBuffers &p_staging_buffers) {265StagingBufferBlock block;266267block.driver_id = driver->buffer_create(p_staging_buffers.block_size, p_staging_buffers.usage_bits, RDD::MEMORY_ALLOCATION_TYPE_CPU);268ERR_FAIL_COND_V(!block.driver_id, ERR_CANT_CREATE);269270block.frame_used = 0;271block.fill_amount = 0;272273p_staging_buffers.blocks.insert(p_staging_buffers.current, block);274return OK;275}276277Error RenderingDevice::_staging_buffer_allocate(StagingBuffers &p_staging_buffers, uint32_t p_amount, uint32_t p_required_align, uint32_t &r_alloc_offset, uint32_t &r_alloc_size, StagingRequiredAction &r_required_action, bool p_can_segment) {278// Determine a block to use.279280r_alloc_size = p_amount;281r_required_action = STAGING_REQUIRED_ACTION_NONE;282283while (true) {284r_alloc_offset = 0;285286// See if we can use current block.287if (p_staging_buffers.blocks[p_staging_buffers.current].frame_used == frames_drawn) {288// We used this block this frame, let's see if there is still room.289290uint32_t write_from = p_staging_buffers.blocks[p_staging_buffers.current].fill_amount;291292{293uint32_t align_remainder = write_from % p_required_align;294if (align_remainder != 0) {295write_from += p_required_align - align_remainder;296}297}298299int32_t available_bytes = int32_t(p_staging_buffers.block_size) - int32_t(write_from);300301if ((int32_t)p_amount < available_bytes) {302// All is good, we should be ok, all will fit.303r_alloc_offset = write_from;304} else if (p_can_segment && available_bytes >= (int32_t)p_required_align) {305// Ok all won't fit but at least we can fit a chunkie.306// All is good, update what needs to be written to.307r_alloc_offset = write_from;308r_alloc_size = available_bytes - (available_bytes % p_required_align);309310} else {311// Can't fit it into this buffer.312// Will need to try next buffer.313314p_staging_buffers.current = (p_staging_buffers.current + 1) % p_staging_buffers.blocks.size();315316// Before doing anything, though, let's check that we didn't manage to fill all blocks.317// Possible in a single frame.318if (p_staging_buffers.blocks[p_staging_buffers.current].frame_used == frames_drawn) {319// Guess we did.. ok, let's see if we can insert a new block.320if ((uint64_t)p_staging_buffers.blocks.size() * p_staging_buffers.block_size < p_staging_buffers.max_size) {321// We can, so we are safe.322Error err = _insert_staging_block(p_staging_buffers);323if (err) {324return err;325}326// Claim for this frame.327p_staging_buffers.blocks.write[p_staging_buffers.current].frame_used = frames_drawn;328} else {329// Ok, worst case scenario, all the staging buffers belong to this frame330// and this frame is not even done.331// If this is the main thread, it means the user is likely loading a lot of resources at once,.332// Otherwise, the thread should just be blocked until the next frame (currently unimplemented).333r_required_action = STAGING_REQUIRED_ACTION_FLUSH_AND_STALL_ALL;334}335336} else {337// Not from current frame, so continue and try again.338continue;339}340}341342} else if (p_staging_buffers.blocks[p_staging_buffers.current].frame_used <= frames_drawn - frames.size()) {343// This is an old block, which was already processed, let's reuse.344p_staging_buffers.blocks.write[p_staging_buffers.current].frame_used = frames_drawn;345p_staging_buffers.blocks.write[p_staging_buffers.current].fill_amount = 0;346} else {347// This block may still be in use, let's not touch it unless we have to, so.. can we create a new one?348if ((uint64_t)p_staging_buffers.blocks.size() * p_staging_buffers.block_size < p_staging_buffers.max_size) {349// We are still allowed to create a new block, so let's do that and insert it for current pos.350Error err = _insert_staging_block(p_staging_buffers);351if (err) {352return err;353}354// Claim for this frame.355p_staging_buffers.blocks.write[p_staging_buffers.current].frame_used = frames_drawn;356} else {357// Oops, we are out of room and we can't create more.358// Let's flush older frames.359// 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.360// If loading from a separate thread, we can block that thread until next frame when more room is made (not currently implemented, though).361r_required_action = STAGING_REQUIRED_ACTION_STALL_PREVIOUS;362}363}364365// All was good, break.366break;367}368369p_staging_buffers.used = true;370371return OK;372}373374void RenderingDevice::_staging_buffer_execute_required_action(StagingBuffers &p_staging_buffers, StagingRequiredAction p_required_action) {375switch (p_required_action) {376case STAGING_REQUIRED_ACTION_NONE: {377// Do nothing.378} break;379case STAGING_REQUIRED_ACTION_FLUSH_AND_STALL_ALL: {380_flush_and_stall_for_all_frames();381382// Clear the whole staging buffer.383for (int i = 0; i < p_staging_buffers.blocks.size(); i++) {384p_staging_buffers.blocks.write[i].frame_used = 0;385p_staging_buffers.blocks.write[i].fill_amount = 0;386}387388// Claim for current frame.389p_staging_buffers.blocks.write[p_staging_buffers.current].frame_used = frames_drawn;390} break;391case STAGING_REQUIRED_ACTION_STALL_PREVIOUS: {392_stall_for_previous_frames();393394for (int i = 0; i < p_staging_buffers.blocks.size(); i++) {395// Clear all blocks but the ones from this frame.396int block_idx = (i + p_staging_buffers.current) % p_staging_buffers.blocks.size();397if (p_staging_buffers.blocks[block_idx].frame_used == frames_drawn) {398break; // Ok, we reached something from this frame, abort.399}400401p_staging_buffers.blocks.write[block_idx].frame_used = 0;402p_staging_buffers.blocks.write[block_idx].fill_amount = 0;403}404405// Claim for current frame.406p_staging_buffers.blocks.write[p_staging_buffers.current].frame_used = frames_drawn;407} break;408default: {409DEV_ASSERT(false && "Unknown required action.");410} break;411}412}413414Error RenderingDevice::buffer_copy(RID p_src_buffer, RID p_dst_buffer, uint32_t p_src_offset, uint32_t p_dst_offset, uint32_t p_size) {415ERR_RENDER_THREAD_GUARD_V(ERR_UNAVAILABLE);416417ERR_FAIL_COND_V_MSG(draw_list.active, ERR_INVALID_PARAMETER,418"Copying buffers is forbidden during creation of a draw list");419ERR_FAIL_COND_V_MSG(compute_list.active, ERR_INVALID_PARAMETER,420"Copying buffers is forbidden during creation of a compute list");421422Buffer *src_buffer = _get_buffer_from_owner(p_src_buffer);423if (!src_buffer) {424ERR_FAIL_V_MSG(ERR_INVALID_PARAMETER, "Source buffer argument is not a valid buffer of any type.");425}426427Buffer *dst_buffer = _get_buffer_from_owner(p_dst_buffer);428if (!dst_buffer) {429ERR_FAIL_V_MSG(ERR_INVALID_PARAMETER, "Destination buffer argument is not a valid buffer of any type.");430}431432// Validate the copy's dimensions for both buffers.433ERR_FAIL_COND_V_MSG((p_size + p_src_offset) > src_buffer->size, ERR_INVALID_PARAMETER, "Size is larger than the source buffer.");434ERR_FAIL_COND_V_MSG((p_size + p_dst_offset) > dst_buffer->size, ERR_INVALID_PARAMETER, "Size is larger than the destination buffer.");435436_check_transfer_worker_buffer(src_buffer);437_check_transfer_worker_buffer(dst_buffer);438439// Perform the copy.440RDD::BufferCopyRegion region;441region.src_offset = p_src_offset;442region.dst_offset = p_dst_offset;443region.size = p_size;444445if (_buffer_make_mutable(dst_buffer, p_dst_buffer)) {446// The destination buffer must be mutable to be used as a copy destination.447draw_graph.add_synchronization();448}449450draw_graph.add_buffer_copy(src_buffer->driver_id, src_buffer->draw_tracker, dst_buffer->driver_id, dst_buffer->draw_tracker, region);451452return OK;453}454455Error RenderingDevice::buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p_size, const void *p_data) {456ERR_RENDER_THREAD_GUARD_V(ERR_UNAVAILABLE);457458copy_bytes_count += p_size;459ERR_FAIL_COND_V_MSG(draw_list.active, ERR_INVALID_PARAMETER,460"Updating buffers is forbidden during creation of a draw list");461ERR_FAIL_COND_V_MSG(compute_list.active, ERR_INVALID_PARAMETER,462"Updating buffers is forbidden during creation of a compute list");463464Buffer *buffer = _get_buffer_from_owner(p_buffer);465ERR_FAIL_NULL_V_MSG(buffer, ERR_INVALID_PARAMETER, "Buffer argument is not a valid buffer of any type.");466ERR_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.");467468_check_transfer_worker_buffer(buffer);469470// Submitting may get chunked for various reasons, so convert this to a task.471size_t to_submit = p_size;472size_t submit_from = 0;473474thread_local LocalVector<RDG::RecordedBufferCopy> command_buffer_copies_vector;475command_buffer_copies_vector.clear();476477const uint8_t *src_data = reinterpret_cast<const uint8_t *>(p_data);478const uint32_t required_align = 32;479while (to_submit > 0) {480uint32_t block_write_offset;481uint32_t block_write_amount;482StagingRequiredAction required_action;483484Error err = _staging_buffer_allocate(upload_staging_buffers, MIN(to_submit, upload_staging_buffers.block_size), required_align, block_write_offset, block_write_amount, required_action);485if (err) {486return err;487}488489if (!command_buffer_copies_vector.is_empty() && required_action == STAGING_REQUIRED_ACTION_FLUSH_AND_STALL_ALL) {490if (_buffer_make_mutable(buffer, p_buffer)) {491// The buffer must be mutable to be used as a copy destination.492draw_graph.add_synchronization();493}494495draw_graph.add_buffer_update(buffer->driver_id, buffer->draw_tracker, command_buffer_copies_vector);496command_buffer_copies_vector.clear();497}498499_staging_buffer_execute_required_action(upload_staging_buffers, required_action);500501// Map staging buffer (It's CPU and coherent).502uint8_t *data_ptr = driver->buffer_map(upload_staging_buffers.blocks[upload_staging_buffers.current].driver_id);503ERR_FAIL_NULL_V(data_ptr, ERR_CANT_CREATE);504505// Copy to staging buffer.506memcpy(data_ptr + block_write_offset, src_data + submit_from, block_write_amount);507508// Unmap.509driver->buffer_unmap(upload_staging_buffers.blocks[upload_staging_buffers.current].driver_id);510511// Insert a command to copy this.512RDD::BufferCopyRegion region;513region.src_offset = block_write_offset;514region.dst_offset = submit_from + p_offset;515region.size = block_write_amount;516517RDG::RecordedBufferCopy buffer_copy;518buffer_copy.source = upload_staging_buffers.blocks[upload_staging_buffers.current].driver_id;519buffer_copy.region = region;520command_buffer_copies_vector.push_back(buffer_copy);521522upload_staging_buffers.blocks.write[upload_staging_buffers.current].fill_amount = block_write_offset + block_write_amount;523524to_submit -= block_write_amount;525submit_from += block_write_amount;526}527528if (!command_buffer_copies_vector.is_empty()) {529if (_buffer_make_mutable(buffer, p_buffer)) {530// The buffer must be mutable to be used as a copy destination.531draw_graph.add_synchronization();532}533534draw_graph.add_buffer_update(buffer->driver_id, buffer->draw_tracker, command_buffer_copies_vector);535}536537gpu_copy_count++;538539return OK;540}541542Error RenderingDevice::driver_callback_add(RDD::DriverCallback p_callback, void *p_userdata, VectorView<CallbackResource> p_resources) {543ERR_RENDER_THREAD_GUARD_V(ERR_UNAVAILABLE);544545ERR_FAIL_COND_V_MSG(draw_list.active, ERR_INVALID_PARAMETER,546"Driver callback is forbidden during creation of a draw list");547ERR_FAIL_COND_V_MSG(compute_list.active, ERR_INVALID_PARAMETER,548"Driver callback is forbidden during creation of a compute list");549550thread_local LocalVector<RDG::ResourceTracker *> trackers;551thread_local LocalVector<RDG::ResourceUsage> usages;552553uint32_t resource_count = p_resources.size();554trackers.resize(resource_count);555usages.resize(resource_count);556557if (resource_count > 0) {558for (uint32_t i = 0; i < p_resources.size(); i++) {559const CallbackResource &cr = p_resources[i];560switch (cr.type) {561case CALLBACK_RESOURCE_TYPE_BUFFER: {562Buffer *buffer = _get_buffer_from_owner(cr.rid);563if (!buffer) {564ERR_FAIL_V_MSG(ERR_INVALID_PARAMETER, vformat("Argument %d is not a valid buffer of any type.", i));565}566if (_buffer_make_mutable(buffer, cr.rid)) {567draw_graph.add_synchronization();568}569trackers[i] = buffer->draw_tracker;570usages[i] = (RDG::ResourceUsage)cr.usage;571} break;572case CALLBACK_RESOURCE_TYPE_TEXTURE: {573Texture *texture = texture_owner.get_or_null(cr.rid);574if (!texture) {575ERR_FAIL_V_MSG(ERR_INVALID_PARAMETER, vformat("Argument %d is not a valid texture.", i));576}577if (_texture_make_mutable(texture, cr.rid)) {578draw_graph.add_synchronization();579}580trackers[i] = texture->draw_tracker;581usages[i] = (RDG::ResourceUsage)cr.usage;582} break;583default: {584CRASH_NOW_MSG("Invalid callback resource type.");585} break;586}587}588}589590draw_graph.add_driver_callback(p_callback, p_userdata, trackers, usages);591592return OK;593}594595String RenderingDevice::get_perf_report() const {596String perf_report_text;597perf_report_text += " gpu:" + String::num_int64(prev_gpu_copy_count);598perf_report_text += " bytes:" + String::num_int64(prev_copy_bytes_count);599600perf_report_text += " lazily alloc:" + String::num_int64(driver->get_lazily_memory_used());601return perf_report_text;602}603604void RenderingDevice::update_perf_report() {605prev_gpu_copy_count = gpu_copy_count;606prev_copy_bytes_count = copy_bytes_count;607gpu_copy_count = 0;608copy_bytes_count = 0;609}610611Error RenderingDevice::buffer_clear(RID p_buffer, uint32_t p_offset, uint32_t p_size) {612ERR_RENDER_THREAD_GUARD_V(ERR_UNAVAILABLE);613614ERR_FAIL_COND_V_MSG((p_size % 4) != 0, ERR_INVALID_PARAMETER,615"Size must be a multiple of four");616ERR_FAIL_COND_V_MSG(draw_list.active, ERR_INVALID_PARAMETER,617"Updating buffers in is forbidden during creation of a draw list");618ERR_FAIL_COND_V_MSG(compute_list.active, ERR_INVALID_PARAMETER,619"Updating buffers is forbidden during creation of a compute list");620621Buffer *buffer = _get_buffer_from_owner(p_buffer);622if (!buffer) {623ERR_FAIL_V_MSG(ERR_INVALID_PARAMETER, "Buffer argument is not a valid buffer of any type.");624}625626ERR_FAIL_COND_V_MSG(p_offset + p_size > buffer->size, ERR_INVALID_PARAMETER,627"Attempted to write buffer (" + itos((p_offset + p_size) - buffer->size) + " bytes) past the end.");628629_check_transfer_worker_buffer(buffer);630631if (_buffer_make_mutable(buffer, p_buffer)) {632// The destination buffer must be mutable to be used as a clear destination.633draw_graph.add_synchronization();634}635636draw_graph.add_buffer_clear(buffer->driver_id, buffer->draw_tracker, p_offset, p_size);637638return OK;639}640641Vector<uint8_t> RenderingDevice::buffer_get_data(RID p_buffer, uint32_t p_offset, uint32_t p_size) {642ERR_RENDER_THREAD_GUARD_V(Vector<uint8_t>());643644Buffer *buffer = _get_buffer_from_owner(p_buffer);645if (!buffer) {646ERR_FAIL_V_MSG(Vector<uint8_t>(), "Buffer is either invalid or this type of buffer can't be retrieved.");647}648649// Size of buffer to retrieve.650if (!p_size) {651p_size = buffer->size;652} else {653ERR_FAIL_COND_V_MSG(p_size + p_offset > buffer->size, Vector<uint8_t>(),654"Size is larger than the buffer.");655}656657_check_transfer_worker_buffer(buffer);658659RDD::BufferID tmp_buffer = driver->buffer_create(buffer->size, RDD::BUFFER_USAGE_TRANSFER_TO_BIT, RDD::MEMORY_ALLOCATION_TYPE_CPU);660ERR_FAIL_COND_V(!tmp_buffer, Vector<uint8_t>());661662RDD::BufferCopyRegion region;663region.src_offset = p_offset;664region.size = p_size;665666draw_graph.add_buffer_get_data(buffer->driver_id, buffer->draw_tracker, tmp_buffer, region);667668// Flush everything so memory can be safely mapped.669_flush_and_stall_for_all_frames();670671uint8_t *buffer_mem = driver->buffer_map(tmp_buffer);672ERR_FAIL_NULL_V(buffer_mem, Vector<uint8_t>());673674Vector<uint8_t> buffer_data;675{676buffer_data.resize(p_size);677uint8_t *w = buffer_data.ptrw();678memcpy(w, buffer_mem, p_size);679}680681driver->buffer_unmap(tmp_buffer);682683driver->buffer_free(tmp_buffer);684685return buffer_data;686}687688Error RenderingDevice::buffer_get_data_async(RID p_buffer, const Callable &p_callback, uint32_t p_offset, uint32_t p_size) {689ERR_RENDER_THREAD_GUARD_V(ERR_UNAVAILABLE);690691Buffer *buffer = _get_buffer_from_owner(p_buffer);692if (buffer == nullptr) {693ERR_FAIL_V_MSG(ERR_INVALID_PARAMETER, "Buffer is either invalid or this type of buffer can't be retrieved.");694}695696if (p_size == 0) {697p_size = buffer->size;698}699700ERR_FAIL_COND_V_MSG(p_size + p_offset > buffer->size, ERR_INVALID_PARAMETER, "Size is larger than the buffer.");701ERR_FAIL_COND_V_MSG(!p_callback.is_valid(), ERR_INVALID_PARAMETER, "Callback must be valid.");702703_check_transfer_worker_buffer(buffer);704705BufferGetDataRequest get_data_request;706get_data_request.callback = p_callback;707get_data_request.frame_local_index = frames[frame].download_buffer_copy_regions.size();708get_data_request.size = p_size;709710const uint32_t required_align = 32;711uint32_t block_write_offset;712uint32_t block_write_amount;713StagingRequiredAction required_action;714uint32_t to_submit = p_size;715uint32_t submit_from = 0;716while (to_submit > 0) {717Error err = _staging_buffer_allocate(download_staging_buffers, MIN(to_submit, download_staging_buffers.block_size), required_align, block_write_offset, block_write_amount, required_action);718if (err) {719return err;720}721722const bool flush_frames = (get_data_request.frame_local_count > 0) && required_action == STAGING_REQUIRED_ACTION_FLUSH_AND_STALL_ALL;723if (flush_frames) {724if (_buffer_make_mutable(buffer, p_buffer)) {725// The buffer must be mutable to be used as a copy source.726draw_graph.add_synchronization();727}728729for (uint32_t i = 0; i < get_data_request.frame_local_count; i++) {730uint32_t local_index = get_data_request.frame_local_index + i;731draw_graph.add_buffer_get_data(buffer->driver_id, buffer->draw_tracker, frames[frame].download_buffer_staging_buffers[local_index], frames[frame].download_buffer_copy_regions[local_index]);732}733}734735_staging_buffer_execute_required_action(download_staging_buffers, required_action);736737if (flush_frames) {738get_data_request.frame_local_count = 0;739get_data_request.frame_local_index = frames[frame].download_buffer_copy_regions.size();740}741742RDD::BufferCopyRegion region;743region.src_offset = submit_from + p_offset;744region.dst_offset = block_write_offset;745region.size = block_write_amount;746747frames[frame].download_buffer_staging_buffers.push_back(download_staging_buffers.blocks[download_staging_buffers.current].driver_id);748frames[frame].download_buffer_copy_regions.push_back(region);749get_data_request.frame_local_count++;750751download_staging_buffers.blocks.write[download_staging_buffers.current].fill_amount = block_write_offset + block_write_amount;752753to_submit -= block_write_amount;754submit_from += block_write_amount;755}756757if (get_data_request.frame_local_count > 0) {758if (_buffer_make_mutable(buffer, p_buffer)) {759// The buffer must be mutable to be used as a copy source.760draw_graph.add_synchronization();761}762763for (uint32_t i = 0; i < get_data_request.frame_local_count; i++) {764uint32_t local_index = get_data_request.frame_local_index + i;765draw_graph.add_buffer_get_data(buffer->driver_id, buffer->draw_tracker, frames[frame].download_buffer_staging_buffers[local_index], frames[frame].download_buffer_copy_regions[local_index]);766}767768frames[frame].download_buffer_get_data_requests.push_back(get_data_request);769}770771return OK;772}773774uint64_t RenderingDevice::buffer_get_device_address(RID p_buffer) {775ERR_RENDER_THREAD_GUARD_V(0);776777Buffer *buffer = _get_buffer_from_owner(p_buffer);778ERR_FAIL_NULL_V_MSG(buffer, 0, "Buffer argument is not a valid buffer of any type.");779ERR_FAIL_COND_V_MSG(!buffer->usage.has_flag(RDD::BUFFER_USAGE_DEVICE_ADDRESS_BIT), 0, "Buffer was not created with device address flag.");780781return driver->buffer_get_device_address(buffer->driver_id);782}783784RID RenderingDevice::storage_buffer_create(uint32_t p_size_bytes, Span<uint8_t> p_data, BitField<StorageBufferUsage> p_usage, BitField<BufferCreationBits> p_creation_bits) {785ERR_FAIL_COND_V(p_data.size() && (uint32_t)p_data.size() != p_size_bytes, RID());786787Buffer buffer;788buffer.size = p_size_bytes;789buffer.usage = (RDD::BUFFER_USAGE_TRANSFER_FROM_BIT | RDD::BUFFER_USAGE_TRANSFER_TO_BIT | RDD::BUFFER_USAGE_STORAGE_BIT);790if (p_usage.has_flag(STORAGE_BUFFER_USAGE_DISPATCH_INDIRECT)) {791buffer.usage.set_flag(RDD::BUFFER_USAGE_INDIRECT_BIT);792}793if (p_creation_bits.has_flag(BUFFER_CREATION_DEVICE_ADDRESS_BIT)) {794#ifdef DEBUG_ENABLED795ERR_FAIL_COND_V_MSG(!has_feature(SUPPORTS_BUFFER_DEVICE_ADDRESS), RID(),796"The GPU doesn't support buffer address flag.");797#endif798799buffer.usage.set_flag(RDD::BUFFER_USAGE_DEVICE_ADDRESS_BIT);800}801buffer.driver_id = driver->buffer_create(buffer.size, buffer.usage, RDD::MEMORY_ALLOCATION_TYPE_GPU);802ERR_FAIL_COND_V(!buffer.driver_id, RID());803804// Storage buffers are assumed to be mutable.805buffer.draw_tracker = RDG::resource_tracker_create();806buffer.draw_tracker->buffer_driver_id = buffer.driver_id;807808if (p_data.size()) {809_buffer_initialize(&buffer, p_data);810}811812_THREAD_SAFE_LOCK_813buffer_memory += buffer.size;814_THREAD_SAFE_UNLOCK_815816RID id = storage_buffer_owner.make_rid(buffer);817#ifdef DEV_ENABLED818set_resource_name(id, "RID:" + itos(id.get_id()));819#endif820return id;821}822823RID RenderingDevice::texture_buffer_create(uint32_t p_size_elements, DataFormat p_format, Span<uint8_t> p_data) {824uint32_t element_size = get_format_vertex_size(p_format);825ERR_FAIL_COND_V_MSG(element_size == 0, RID(), "Format requested is not supported for texture buffers");826uint64_t size_bytes = uint64_t(element_size) * p_size_elements;827828ERR_FAIL_COND_V(p_data.size() && (uint32_t)p_data.size() != size_bytes, RID());829830Buffer texture_buffer;831texture_buffer.size = size_bytes;832BitField<RDD::BufferUsageBits> usage = (RDD::BUFFER_USAGE_TRANSFER_FROM_BIT | RDD::BUFFER_USAGE_TRANSFER_TO_BIT | RDD::BUFFER_USAGE_TEXEL_BIT);833texture_buffer.driver_id = driver->buffer_create(size_bytes, usage, RDD::MEMORY_ALLOCATION_TYPE_GPU);834ERR_FAIL_COND_V(!texture_buffer.driver_id, RID());835836// Texture buffers are assumed to be immutable unless they don't have initial data.837if (p_data.is_empty()) {838texture_buffer.draw_tracker = RDG::resource_tracker_create();839texture_buffer.draw_tracker->buffer_driver_id = texture_buffer.driver_id;840}841842bool ok = driver->buffer_set_texel_format(texture_buffer.driver_id, p_format);843if (!ok) {844driver->buffer_free(texture_buffer.driver_id);845ERR_FAIL_V(RID());846}847848if (p_data.size()) {849_buffer_initialize(&texture_buffer, p_data);850}851852_THREAD_SAFE_LOCK_853buffer_memory += size_bytes;854_THREAD_SAFE_UNLOCK_855856RID id = texture_buffer_owner.make_rid(texture_buffer);857#ifdef DEV_ENABLED858set_resource_name(id, "RID:" + itos(id.get_id()));859#endif860return id;861}862863/*****************/864/**** TEXTURE ****/865/*****************/866867RID RenderingDevice::texture_create(const TextureFormat &p_format, const TextureView &p_view, const Vector<Vector<uint8_t>> &p_data) {868// Some adjustments will happen.869TextureFormat format = p_format;870871if (format.shareable_formats.size()) {872ERR_FAIL_COND_V_MSG(!format.shareable_formats.has(format.format), RID(),873"If supplied a list of shareable formats, the current format must be present in the list");874ERR_FAIL_COND_V_MSG(p_view.format_override != DATA_FORMAT_MAX && !format.shareable_formats.has(p_view.format_override), RID(),875"If supplied a list of shareable formats, the current view format override must be present in the list");876}877878ERR_FAIL_INDEX_V(format.texture_type, RDD::TEXTURE_TYPE_MAX, RID());879880ERR_FAIL_COND_V_MSG(format.width < 1, RID(), "Width must be equal or greater than 1 for all textures");881882if (format.texture_type != TEXTURE_TYPE_1D && format.texture_type != TEXTURE_TYPE_1D_ARRAY) {883ERR_FAIL_COND_V_MSG(format.height < 1, RID(), "Height must be equal or greater than 1 for 2D and 3D textures");884}885886if (format.texture_type == TEXTURE_TYPE_3D) {887ERR_FAIL_COND_V_MSG(format.depth < 1, RID(), "Depth must be equal or greater than 1 for 3D textures");888}889890ERR_FAIL_COND_V(format.mipmaps < 1, RID());891892if (format.texture_type == TEXTURE_TYPE_1D_ARRAY || format.texture_type == TEXTURE_TYPE_2D_ARRAY || format.texture_type == TEXTURE_TYPE_CUBE_ARRAY || format.texture_type == TEXTURE_TYPE_CUBE) {893ERR_FAIL_COND_V_MSG(format.array_layers < 1, RID(),894"Number of layers must be equal or greater than 1 for arrays and cubemaps.");895ERR_FAIL_COND_V_MSG((format.texture_type == TEXTURE_TYPE_CUBE_ARRAY || format.texture_type == TEXTURE_TYPE_CUBE) && (format.array_layers % 6) != 0, RID(),896"Cubemap and cubemap array textures must provide a layer number that is multiple of 6");897ERR_FAIL_COND_V_MSG(((format.texture_type == TEXTURE_TYPE_CUBE_ARRAY || format.texture_type == TEXTURE_TYPE_CUBE)) && (format.width != format.height), RID(),898"Cubemap and cubemap array textures must have equal width and height.");899ERR_FAIL_COND_V_MSG(format.array_layers > driver->limit_get(LIMIT_MAX_TEXTURE_ARRAY_LAYERS), RID(), "Number of layers exceeds device maximum.");900} else {901format.array_layers = 1;902}903904ERR_FAIL_INDEX_V(format.samples, TEXTURE_SAMPLES_MAX, RID());905906ERR_FAIL_COND_V_MSG(format.usage_bits == 0, RID(), "No usage bits specified (at least one is needed)");907908format.height = format.texture_type != TEXTURE_TYPE_1D && format.texture_type != TEXTURE_TYPE_1D_ARRAY ? format.height : 1;909format.depth = format.texture_type == TEXTURE_TYPE_3D ? format.depth : 1;910911uint64_t size_max = 0;912switch (format.texture_type) {913case TEXTURE_TYPE_1D:914case TEXTURE_TYPE_1D_ARRAY:915size_max = driver->limit_get(LIMIT_MAX_TEXTURE_SIZE_1D);916break;917case TEXTURE_TYPE_2D:918case TEXTURE_TYPE_2D_ARRAY:919size_max = driver->limit_get(LIMIT_MAX_TEXTURE_SIZE_2D);920break;921case TEXTURE_TYPE_CUBE:922case TEXTURE_TYPE_CUBE_ARRAY:923size_max = driver->limit_get(LIMIT_MAX_TEXTURE_SIZE_CUBE);924break;925case TEXTURE_TYPE_3D:926size_max = driver->limit_get(LIMIT_MAX_TEXTURE_SIZE_3D);927break;928case TEXTURE_TYPE_MAX:929break;930}931ERR_FAIL_COND_V_MSG(format.width > size_max || format.height > size_max || format.depth > size_max, RID(), "Texture dimensions exceed device maximum.");932933uint32_t required_mipmaps = get_image_required_mipmaps(format.width, format.height, format.depth);934935ERR_FAIL_COND_V_MSG(required_mipmaps < format.mipmaps, RID(),936"Too many mipmaps requested for texture format and dimensions (" + itos(format.mipmaps) + "), maximum allowed: (" + itos(required_mipmaps) + ").");937938Vector<Vector<uint8_t>> data = p_data;939bool immediate_flush = false;940941// If this is a VRS texture, we make sure that it is created with valid initial data. This prevents a crash on Qualcomm Snapdragon XR2 Gen 1942// (used in Quest 2, Quest Pro, Pico 4, HTC Vive XR Elite and others) where the driver will read the texture before we've had time to finish updating it.943if (data.is_empty() && (p_format.usage_bits & TEXTURE_USAGE_VRS_ATTACHMENT_BIT)) {944immediate_flush = true;945for (uint32_t i = 0; i < format.array_layers; i++) {946uint32_t required_size = get_image_format_required_size(format.format, format.width, format.height, format.depth, format.mipmaps);947Vector<uint8_t> layer;948layer.resize(required_size);949layer.fill(255);950data.push_back(layer);951}952}953954uint32_t forced_usage_bits = _texture_vrs_method_to_usage_bits();955if (data.size()) {956ERR_FAIL_COND_V_MSG(data.size() != (int)format.array_layers, RID(),957"Default supplied data for image format is of invalid length (" + itos(data.size()) + "), should be (" + itos(format.array_layers) + ").");958959for (uint32_t i = 0; i < format.array_layers; i++) {960uint32_t required_size = get_image_format_required_size(format.format, format.width, format.height, format.depth, format.mipmaps);961ERR_FAIL_COND_V_MSG((uint32_t)data[i].size() != required_size, RID(),962"Data for slice index " + itos(i) + " (mapped to layer " + itos(i) + ") differs in size (supplied: " + itos(data[i].size()) + ") than what is required by the format (" + itos(required_size) + ").");963}964965ERR_FAIL_COND_V_MSG(format.usage_bits & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, RID(),966"Textures created as depth attachments can't be initialized with data directly. Use RenderingDevice::texture_update() instead.");967968if (!(format.usage_bits & TEXTURE_USAGE_CAN_UPDATE_BIT)) {969forced_usage_bits |= TEXTURE_USAGE_CAN_UPDATE_BIT;970}971}972973{974// Validate that this image is supported for the intended use.975bool cpu_readable = (format.usage_bits & RDD::TEXTURE_USAGE_CPU_READ_BIT);976BitField<RDD::TextureUsageBits> supported_usage = driver->texture_get_usages_supported_by_format(format.format, cpu_readable);977978String format_text = "'" + String(FORMAT_NAMES[format.format]) + "'";979980if ((format.usage_bits & TEXTURE_USAGE_SAMPLING_BIT) && !supported_usage.has_flag(TEXTURE_USAGE_SAMPLING_BIT)) {981ERR_FAIL_V_MSG(RID(), "Format " + format_text + " does not support usage as sampling texture.");982}983if ((format.usage_bits & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) && !supported_usage.has_flag(TEXTURE_USAGE_COLOR_ATTACHMENT_BIT)) {984ERR_FAIL_V_MSG(RID(), "Format " + format_text + " does not support usage as color attachment.");985}986if ((format.usage_bits & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) && !supported_usage.has_flag(TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) {987ERR_FAIL_V_MSG(RID(), "Format " + format_text + " does not support usage as depth-stencil attachment.");988}989if ((format.usage_bits & TEXTURE_USAGE_STORAGE_BIT) && !supported_usage.has_flag(TEXTURE_USAGE_STORAGE_BIT)) {990ERR_FAIL_V_MSG(RID(), "Format " + format_text + " does not support usage as storage image.");991}992if ((format.usage_bits & TEXTURE_USAGE_STORAGE_ATOMIC_BIT) && !supported_usage.has_flag(TEXTURE_USAGE_STORAGE_ATOMIC_BIT)) {993ERR_FAIL_V_MSG(RID(), "Format " + format_text + " does not support usage as atomic storage image.");994}995if ((format.usage_bits & TEXTURE_USAGE_VRS_ATTACHMENT_BIT) && !supported_usage.has_flag(TEXTURE_USAGE_VRS_ATTACHMENT_BIT)) {996ERR_FAIL_V_MSG(RID(), "Format " + format_text + " does not support usage as variable shading rate attachment.");997}998}9991000// Transfer and validate view info.10011002RDD::TextureView tv;1003if (p_view.format_override == DATA_FORMAT_MAX) {1004tv.format = format.format;1005} else {1006ERR_FAIL_INDEX_V(p_view.format_override, DATA_FORMAT_MAX, RID());1007tv.format = p_view.format_override;1008}1009ERR_FAIL_INDEX_V(p_view.swizzle_r, TEXTURE_SWIZZLE_MAX, RID());1010ERR_FAIL_INDEX_V(p_view.swizzle_g, TEXTURE_SWIZZLE_MAX, RID());1011ERR_FAIL_INDEX_V(p_view.swizzle_b, TEXTURE_SWIZZLE_MAX, RID());1012ERR_FAIL_INDEX_V(p_view.swizzle_a, TEXTURE_SWIZZLE_MAX, RID());1013tv.swizzle_r = p_view.swizzle_r;1014tv.swizzle_g = p_view.swizzle_g;1015tv.swizzle_b = p_view.swizzle_b;1016tv.swizzle_a = p_view.swizzle_a;10171018// Create.10191020Texture texture;1021format.usage_bits |= forced_usage_bits;1022texture.driver_id = driver->texture_create(format, tv);1023ERR_FAIL_COND_V(!texture.driver_id, RID());1024texture.type = format.texture_type;1025texture.format = format.format;1026texture.width = format.width;1027texture.height = format.height;1028texture.depth = format.depth;1029texture.layers = format.array_layers;1030texture.mipmaps = format.mipmaps;1031texture.base_mipmap = 0;1032texture.base_layer = 0;1033texture.is_resolve_buffer = format.is_resolve_buffer;1034texture.is_discardable = format.is_discardable;1035texture.usage_flags = format.usage_bits & ~forced_usage_bits;1036texture.samples = format.samples;1037texture.allowed_shared_formats = format.shareable_formats;1038texture.has_initial_data = !data.is_empty();10391040if ((format.usage_bits & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) {1041texture.read_aspect_flags.set_flag(RDD::TEXTURE_ASPECT_DEPTH_BIT);1042texture.barrier_aspect_flags.set_flag(RDD::TEXTURE_ASPECT_DEPTH_BIT);1043if (format_has_stencil(format.format)) {1044texture.barrier_aspect_flags.set_flag(RDD::TEXTURE_ASPECT_STENCIL_BIT);1045}1046} else {1047texture.read_aspect_flags.set_flag(RDD::TEXTURE_ASPECT_COLOR_BIT);1048texture.barrier_aspect_flags.set_flag(RDD::TEXTURE_ASPECT_COLOR_BIT);1049}10501051texture.bound = false;10521053// Textures are only assumed to be immutable if they have initial data and none of the other bits that indicate write usage are enabled.1054bool texture_mutable_by_default = texture.usage_flags & (TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | TEXTURE_USAGE_STORAGE_BIT | TEXTURE_USAGE_STORAGE_ATOMIC_BIT);1055if (data.is_empty() || texture_mutable_by_default) {1056_texture_make_mutable(&texture, RID());1057}10581059texture_memory += driver->texture_get_allocation_size(texture.driver_id);10601061RID id = texture_owner.make_rid(texture);1062#ifdef DEV_ENABLED1063set_resource_name(id, "RID:" + itos(id.get_id()));1064#endif10651066if (data.size()) {1067const bool use_general_in_copy_queues = driver->api_trait_get(RDD::API_TRAIT_USE_GENERAL_IN_COPY_QUEUES);1068const RDD::TextureLayout dst_layout = use_general_in_copy_queues ? RDD::TEXTURE_LAYOUT_GENERAL : RDD::TEXTURE_LAYOUT_COPY_DST_OPTIMAL;1069for (uint32_t i = 0; i < format.array_layers; i++) {1070_texture_initialize(id, i, data[i], dst_layout, immediate_flush);1071}10721073if (texture.draw_tracker != nullptr) {1074texture.draw_tracker->usage = use_general_in_copy_queues ? RDG::RESOURCE_USAGE_GENERAL : RDG::RESOURCE_USAGE_COPY_TO;1075}1076}10771078return id;1079}10801081RID RenderingDevice::texture_create_shared(const TextureView &p_view, RID p_with_texture) {1082Texture *src_texture = texture_owner.get_or_null(p_with_texture);1083ERR_FAIL_NULL_V(src_texture, RID());10841085if (src_texture->owner.is_valid()) { // Ahh this is a share. The RenderingDeviceDriver needs the actual owner.1086p_with_texture = src_texture->owner;1087src_texture = texture_owner.get_or_null(src_texture->owner);1088ERR_FAIL_NULL_V(src_texture, RID()); // This is a bug.1089}10901091// Create view.10921093Texture texture = *src_texture;1094texture.slice_trackers = nullptr;1095texture.shared_fallback = nullptr;10961097RDD::TextureView tv;1098bool create_shared = true;1099bool raw_reintepretation = false;1100if (p_view.format_override == DATA_FORMAT_MAX || p_view.format_override == texture.format) {1101tv.format = texture.format;1102} else {1103ERR_FAIL_INDEX_V(p_view.format_override, DATA_FORMAT_MAX, RID());11041105ERR_FAIL_COND_V_MSG(!texture.allowed_shared_formats.has(p_view.format_override), RID(),1106"Format override is not in the list of allowed shareable formats for original texture.");1107tv.format = p_view.format_override;1108create_shared = driver->texture_can_make_shared_with_format(texture.driver_id, p_view.format_override, raw_reintepretation);1109}1110tv.swizzle_r = p_view.swizzle_r;1111tv.swizzle_g = p_view.swizzle_g;1112tv.swizzle_b = p_view.swizzle_b;1113tv.swizzle_a = p_view.swizzle_a;11141115if (create_shared) {1116texture.driver_id = driver->texture_create_shared(texture.driver_id, tv);1117} else {1118// The regular view will use the same format as the main texture.1119RDD::TextureView regular_view = tv;1120regular_view.format = src_texture->format;1121texture.driver_id = driver->texture_create_shared(texture.driver_id, regular_view);11221123// Create the independent texture for the alias.1124RDD::TextureFormat alias_format = texture.texture_format();1125alias_format.format = tv.format;1126alias_format.usage_bits = TEXTURE_USAGE_SAMPLING_BIT | TEXTURE_USAGE_CAN_COPY_TO_BIT;11271128_texture_check_shared_fallback(src_texture);1129_texture_check_shared_fallback(&texture);11301131texture.shared_fallback->texture = driver->texture_create(alias_format, tv);1132texture.shared_fallback->raw_reinterpretation = raw_reintepretation;1133texture_memory += driver->texture_get_allocation_size(texture.shared_fallback->texture);11341135RDG::ResourceTracker *tracker = RDG::resource_tracker_create();1136tracker->texture_driver_id = texture.shared_fallback->texture;1137tracker->texture_size = Size2i(texture.width, texture.height);1138tracker->texture_subresources = texture.barrier_range();1139tracker->texture_usage = alias_format.usage_bits;1140tracker->is_discardable = texture.is_discardable;1141tracker->reference_count = 1;1142texture.shared_fallback->texture_tracker = tracker;1143texture.shared_fallback->revision = 0;11441145if (raw_reintepretation && src_texture->shared_fallback->buffer.id == 0) {1146// For shared textures of the same size, we create the buffer on the main texture if it doesn't have it already.1147_texture_create_reinterpret_buffer(src_texture);1148}1149}11501151ERR_FAIL_COND_V(!texture.driver_id, RID());11521153if (texture.draw_tracker != nullptr) {1154texture.draw_tracker->reference_count++;1155}11561157texture.owner = p_with_texture;1158RID id = texture_owner.make_rid(texture);1159#ifdef DEV_ENABLED1160set_resource_name(id, "RID:" + itos(id.get_id()));1161#endif1162_add_dependency(id, p_with_texture);11631164return id;1165}11661167RID RenderingDevice::texture_create_from_extension(TextureType p_type, DataFormat p_format, TextureSamples p_samples, BitField<RenderingDevice::TextureUsageBits> p_usage, uint64_t p_image, uint64_t p_width, uint64_t p_height, uint64_t p_depth, uint64_t p_layers, uint64_t p_mipmaps) {1168// This method creates a texture object using a VkImage created by an extension, module or other external source (OpenXR uses this).11691170Texture texture;1171texture.type = p_type;1172texture.format = p_format;1173texture.samples = p_samples;1174texture.width = p_width;1175texture.height = p_height;1176texture.depth = p_depth;1177texture.layers = p_layers;1178texture.mipmaps = p_mipmaps;1179texture.usage_flags = p_usage;1180texture.base_mipmap = 0;1181texture.base_layer = 0;1182texture.allowed_shared_formats.push_back(RD::DATA_FORMAT_R8G8B8A8_UNORM);1183texture.allowed_shared_formats.push_back(RD::DATA_FORMAT_R8G8B8A8_SRGB);11841185if (p_usage.has_flag(TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) {1186texture.read_aspect_flags.set_flag(RDD::TEXTURE_ASPECT_DEPTH_BIT);1187texture.barrier_aspect_flags.set_flag(RDD::TEXTURE_ASPECT_DEPTH_BIT);1188/*if (format_has_stencil(p_format.format)) {1189texture.barrier_aspect_flags.set_flag(RDD::TEXTURE_ASPECT_STENCIL_BIT);1190}*/1191} else {1192texture.read_aspect_flags.set_flag(RDD::TEXTURE_ASPECT_COLOR_BIT);1193texture.barrier_aspect_flags.set_flag(RDD::TEXTURE_ASPECT_COLOR_BIT);1194}11951196texture.driver_id = driver->texture_create_from_extension(p_image, p_type, p_format, p_layers, (texture.usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT), p_mipmaps);1197ERR_FAIL_COND_V(!texture.driver_id, RID());11981199_texture_make_mutable(&texture, RID());12001201RID id = texture_owner.make_rid(texture);1202#ifdef DEV_ENABLED1203set_resource_name(id, "RID:" + itos(id.get_id()));1204#endif12051206return id;1207}12081209RID RenderingDevice::texture_create_shared_from_slice(const TextureView &p_view, RID p_with_texture, uint32_t p_layer, uint32_t p_mipmap, uint32_t p_mipmaps, TextureSliceType p_slice_type, uint32_t p_layers) {1210Texture *src_texture = texture_owner.get_or_null(p_with_texture);1211ERR_FAIL_NULL_V(src_texture, RID());12121213if (src_texture->owner.is_valid()) { // // Ahh this is a share. The RenderingDeviceDriver needs the actual owner.1214p_with_texture = src_texture->owner;1215src_texture = texture_owner.get_or_null(src_texture->owner);1216ERR_FAIL_NULL_V(src_texture, RID()); // This is a bug.1217}12181219ERR_FAIL_COND_V_MSG(p_slice_type == TEXTURE_SLICE_CUBEMAP && (src_texture->type != TEXTURE_TYPE_CUBE && src_texture->type != TEXTURE_TYPE_CUBE_ARRAY), RID(),1220"Can only create a cubemap slice from a cubemap or cubemap array mipmap");12211222ERR_FAIL_COND_V_MSG(p_slice_type == TEXTURE_SLICE_3D && src_texture->type != TEXTURE_TYPE_3D, RID(),1223"Can only create a 3D slice from a 3D texture");12241225ERR_FAIL_COND_V_MSG(p_slice_type == TEXTURE_SLICE_2D_ARRAY && (src_texture->type != TEXTURE_TYPE_2D_ARRAY), RID(),1226"Can only create an array slice from a 2D array mipmap");12271228// Create view.12291230ERR_FAIL_UNSIGNED_INDEX_V(p_mipmap, src_texture->mipmaps, RID());1231ERR_FAIL_COND_V(p_mipmap + p_mipmaps > src_texture->mipmaps, RID());1232ERR_FAIL_UNSIGNED_INDEX_V(p_layer, src_texture->layers, RID());12331234int slice_layers = 1;1235if (p_layers != 0) {1236ERR_FAIL_COND_V_MSG(p_layers > 1 && p_slice_type != TEXTURE_SLICE_2D_ARRAY, RID(), "layer slicing only supported for 2D arrays");1237ERR_FAIL_COND_V_MSG(p_layer + p_layers > src_texture->layers, RID(), "layer slice is out of bounds");1238slice_layers = p_layers;1239} else if (p_slice_type == TEXTURE_SLICE_2D_ARRAY) {1240ERR_FAIL_COND_V_MSG(p_layer != 0, RID(), "layer must be 0 when obtaining a 2D array mipmap slice");1241slice_layers = src_texture->layers;1242} else if (p_slice_type == TEXTURE_SLICE_CUBEMAP) {1243slice_layers = 6;1244}12451246Texture texture = *src_texture;1247texture.slice_trackers = nullptr;1248texture.shared_fallback = nullptr;12491250get_image_format_required_size(texture.format, texture.width, texture.height, texture.depth, p_mipmap + 1, &texture.width, &texture.height);1251texture.mipmaps = p_mipmaps;1252texture.layers = slice_layers;1253texture.base_mipmap = p_mipmap;1254texture.base_layer = p_layer;12551256if (p_slice_type == TEXTURE_SLICE_2D) {1257texture.type = TEXTURE_TYPE_2D;1258} else if (p_slice_type == TEXTURE_SLICE_3D) {1259texture.type = TEXTURE_TYPE_3D;1260}12611262RDD::TextureView tv;1263bool create_shared = true;1264bool raw_reintepretation = false;1265if (p_view.format_override == DATA_FORMAT_MAX || p_view.format_override == texture.format) {1266tv.format = texture.format;1267} else {1268ERR_FAIL_INDEX_V(p_view.format_override, DATA_FORMAT_MAX, RID());12691270ERR_FAIL_COND_V_MSG(!texture.allowed_shared_formats.has(p_view.format_override), RID(),1271"Format override is not in the list of allowed shareable formats for original texture.");1272tv.format = p_view.format_override;1273create_shared = driver->texture_can_make_shared_with_format(texture.driver_id, p_view.format_override, raw_reintepretation);1274}12751276tv.swizzle_r = p_view.swizzle_r;1277tv.swizzle_g = p_view.swizzle_g;1278tv.swizzle_b = p_view.swizzle_b;1279tv.swizzle_a = p_view.swizzle_a;12801281if (p_slice_type == TEXTURE_SLICE_CUBEMAP) {1282ERR_FAIL_COND_V_MSG(p_layer >= src_texture->layers, RID(),1283"Specified layer is invalid for cubemap");1284ERR_FAIL_COND_V_MSG((p_layer % 6) != 0, RID(),1285"Specified layer must be a multiple of 6.");1286}12871288if (create_shared) {1289texture.driver_id = driver->texture_create_shared_from_slice(src_texture->driver_id, tv, p_slice_type, p_layer, slice_layers, p_mipmap, p_mipmaps);1290} else {1291// The regular view will use the same format as the main texture.1292RDD::TextureView regular_view = tv;1293regular_view.format = src_texture->format;1294texture.driver_id = driver->texture_create_shared_from_slice(src_texture->driver_id, regular_view, p_slice_type, p_layer, slice_layers, p_mipmap, p_mipmaps);12951296// Create the independent texture for the slice.1297RDD::TextureSubresourceRange slice_range = texture.barrier_range();1298slice_range.base_mipmap = 0;1299slice_range.base_layer = 0;13001301RDD::TextureFormat slice_format = texture.texture_format();1302slice_format.width = MAX(texture.width >> p_mipmap, 1U);1303slice_format.height = MAX(texture.height >> p_mipmap, 1U);1304slice_format.depth = MAX(texture.depth >> p_mipmap, 1U);1305slice_format.format = tv.format;1306slice_format.usage_bits = TEXTURE_USAGE_SAMPLING_BIT | TEXTURE_USAGE_CAN_COPY_TO_BIT;13071308_texture_check_shared_fallback(src_texture);1309_texture_check_shared_fallback(&texture);13101311texture.shared_fallback->texture = driver->texture_create(slice_format, tv);1312texture.shared_fallback->raw_reinterpretation = raw_reintepretation;1313texture_memory += driver->texture_get_allocation_size(texture.shared_fallback->texture);13141315RDG::ResourceTracker *tracker = RDG::resource_tracker_create();1316tracker->texture_driver_id = texture.shared_fallback->texture;1317tracker->texture_size = Size2i(texture.width, texture.height);1318tracker->texture_subresources = slice_range;1319tracker->texture_usage = slice_format.usage_bits;1320tracker->is_discardable = slice_format.is_discardable;1321tracker->reference_count = 1;1322texture.shared_fallback->texture_tracker = tracker;1323texture.shared_fallback->revision = 0;13241325if (raw_reintepretation && src_texture->shared_fallback->buffer.id == 0) {1326// For shared texture slices, we create the buffer on the slice if the source texture has no reinterpretation buffer.1327_texture_create_reinterpret_buffer(&texture);1328}1329}13301331ERR_FAIL_COND_V(!texture.driver_id, RID());13321333const Rect2i slice_rect(p_mipmap, p_layer, p_mipmaps, slice_layers);1334texture.owner = p_with_texture;1335texture.slice_type = p_slice_type;1336texture.slice_rect = slice_rect;13371338// If parent is mutable, make slice mutable by default.1339if (src_texture->draw_tracker != nullptr) {1340texture.draw_tracker = nullptr;1341_texture_make_mutable(&texture, RID());1342}13431344RID id = texture_owner.make_rid(texture);1345#ifdef DEV_ENABLED1346set_resource_name(id, "RID:" + itos(id.get_id()));1347#endif1348_add_dependency(id, p_with_texture);13491350return id;1351}13521353static _ALWAYS_INLINE_ void _copy_region(uint8_t const *__restrict p_src, uint8_t *__restrict p_dst, uint32_t p_src_x, uint32_t p_src_y, uint32_t p_src_w, uint32_t p_src_h, uint32_t p_src_full_w, uint32_t p_dst_pitch, uint32_t p_unit_size) {1354uint32_t src_offset = (p_src_y * p_src_full_w + p_src_x) * p_unit_size;1355uint32_t dst_offset = 0;1356for (uint32_t y = p_src_h; y > 0; y--) {1357uint8_t const *__restrict src = p_src + src_offset;1358uint8_t *__restrict dst = p_dst + dst_offset;1359for (uint32_t x = p_src_w * p_unit_size; x > 0; x--) {1360*dst = *src;1361src++;1362dst++;1363}1364src_offset += p_src_full_w * p_unit_size;1365dst_offset += p_dst_pitch;1366}1367}13681369static _ALWAYS_INLINE_ void _copy_region_block_or_regular(const uint8_t *p_read_ptr, uint8_t *p_write_ptr, uint32_t p_x, uint32_t p_y, uint32_t p_width, uint32_t p_region_w, uint32_t p_region_h, uint32_t p_block_w, uint32_t p_block_h, uint32_t p_dst_pitch, uint32_t p_pixel_size, uint32_t p_block_size) {1370if (p_block_w != 1 || p_block_h != 1) {1371// Block format.1372uint32_t xb = p_x / p_block_w;1373uint32_t yb = p_y / p_block_h;1374uint32_t wb = p_width / p_block_w;1375uint32_t region_wb = p_region_w / p_block_w;1376uint32_t region_hb = p_region_h / p_block_h;1377_copy_region(p_read_ptr, p_write_ptr, xb, yb, region_wb, region_hb, wb, p_dst_pitch, p_block_size);1378} else {1379// Regular format.1380_copy_region(p_read_ptr, p_write_ptr, p_x, p_y, p_region_w, p_region_h, p_width, p_dst_pitch, p_pixel_size);1381}1382}13831384uint32_t RenderingDevice::_texture_layer_count(Texture *p_texture) const {1385switch (p_texture->type) {1386case TEXTURE_TYPE_CUBE:1387case TEXTURE_TYPE_CUBE_ARRAY:1388return p_texture->layers * 6;1389default:1390return p_texture->layers;1391}1392}13931394uint32_t greatest_common_denominator(uint32_t a, uint32_t b) {1395// Euclidean algorithm.1396uint32_t t;1397while (b != 0) {1398t = b;1399b = a % b;1400a = t;1401}14021403return a;1404}14051406uint32_t least_common_multiple(uint32_t a, uint32_t b) {1407if (a == 0 || b == 0) {1408return 0;1409}14101411return (a / greatest_common_denominator(a, b)) * b;1412}14131414uint32_t RenderingDevice::_texture_alignment(Texture *p_texture) const {1415uint32_t alignment = get_compressed_image_format_block_byte_size(p_texture->format);1416if (alignment == 1) {1417alignment = get_image_format_pixel_size(p_texture->format);1418}14191420return least_common_multiple(alignment, driver->api_trait_get(RDD::API_TRAIT_TEXTURE_TRANSFER_ALIGNMENT));1421}14221423Error RenderingDevice::_texture_initialize(RID p_texture, uint32_t p_layer, const Vector<uint8_t> &p_data, RDD::TextureLayout p_dst_layout, bool p_immediate_flush) {1424Texture *texture = texture_owner.get_or_null(p_texture);1425ERR_FAIL_NULL_V(texture, ERR_INVALID_PARAMETER);14261427if (texture->owner != RID()) {1428p_texture = texture->owner;1429texture = texture_owner.get_or_null(texture->owner);1430ERR_FAIL_NULL_V(texture, ERR_BUG); // This is a bug.1431}14321433uint32_t layer_count = _texture_layer_count(texture);1434ERR_FAIL_COND_V(p_layer >= layer_count, ERR_INVALID_PARAMETER);14351436uint32_t width, height;1437uint32_t tight_mip_size = get_image_format_required_size(texture->format, texture->width, texture->height, texture->depth, texture->mipmaps, &width, &height);1438uint32_t required_size = tight_mip_size;1439uint32_t required_align = _texture_alignment(texture);14401441ERR_FAIL_COND_V_MSG(required_size != (uint32_t)p_data.size(), ERR_INVALID_PARAMETER,1442"Required size for texture update (" + itos(required_size) + ") does not match data supplied size (" + itos(p_data.size()) + ").");14431444uint32_t block_w, block_h;1445get_compressed_image_format_block_dimensions(texture->format, block_w, block_h);14461447uint32_t pixel_size = get_image_format_pixel_size(texture->format);1448uint32_t pixel_rshift = get_compressed_image_format_pixel_rshift(texture->format);1449uint32_t block_size = get_compressed_image_format_block_byte_size(texture->format);14501451// The algorithm operates on two passes, one to figure out the total size the staging buffer will require to allocate and another one where the copy is actually performed.1452uint32_t staging_worker_offset = 0;1453uint32_t staging_local_offset = 0;1454TransferWorker *transfer_worker = nullptr;1455const uint8_t *read_ptr = p_data.ptr();1456uint8_t *write_ptr = nullptr;1457for (uint32_t pass = 0; pass < 2; pass++) {1458const bool copy_pass = (pass == 1);1459if (copy_pass) {1460transfer_worker = _acquire_transfer_worker(staging_local_offset, required_align, staging_worker_offset);1461texture->transfer_worker_index = transfer_worker->index;14621463{1464MutexLock lock(transfer_worker->operations_mutex);1465texture->transfer_worker_operation = ++transfer_worker->operations_counter;1466}14671468staging_local_offset = 0;14691470write_ptr = driver->buffer_map(transfer_worker->staging_buffer);1471ERR_FAIL_NULL_V(write_ptr, ERR_CANT_CREATE);14721473if (driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) {1474// Transition the texture to the optimal layout.1475RDD::TextureBarrier tb;1476tb.texture = texture->driver_id;1477tb.dst_access = RDD::BARRIER_ACCESS_COPY_WRITE_BIT;1478tb.prev_layout = RDD::TEXTURE_LAYOUT_UNDEFINED;1479tb.next_layout = p_dst_layout;1480tb.subresources.aspect = texture->barrier_aspect_flags;1481tb.subresources.mipmap_count = texture->mipmaps;1482tb.subresources.base_layer = p_layer;1483tb.subresources.layer_count = 1;1484driver->command_pipeline_barrier(transfer_worker->command_buffer, RDD::PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, RDD::PIPELINE_STAGE_COPY_BIT, {}, {}, tb);1485}1486}14871488uint32_t mipmap_offset = 0;1489uint32_t logic_width = texture->width;1490uint32_t logic_height = texture->height;1491for (uint32_t mm_i = 0; mm_i < texture->mipmaps; mm_i++) {1492uint32_t depth = 0;1493uint32_t image_total = get_image_format_required_size(texture->format, texture->width, texture->height, texture->depth, mm_i + 1, &width, &height, &depth);14941495const uint8_t *read_ptr_mipmap = read_ptr + mipmap_offset;1496tight_mip_size = image_total - mipmap_offset;14971498for (uint32_t z = 0; z < depth; z++) {1499if (required_align > 0) {1500uint32_t align_offset = staging_local_offset % required_align;1501if (align_offset != 0) {1502staging_local_offset += required_align - align_offset;1503}1504}15051506uint32_t pitch = (width * pixel_size * block_w) >> pixel_rshift;1507uint32_t pitch_step = driver->api_trait_get(RDD::API_TRAIT_TEXTURE_DATA_ROW_PITCH_STEP);1508pitch = STEPIFY(pitch, pitch_step);1509uint32_t to_allocate = pitch * height;1510to_allocate >>= pixel_rshift;15111512if (copy_pass) {1513const uint8_t *read_ptr_mipmap_layer = read_ptr_mipmap + (tight_mip_size / depth) * z;1514uint64_t staging_buffer_offset = staging_worker_offset + staging_local_offset;1515uint8_t *write_ptr_mipmap_layer = write_ptr + staging_buffer_offset;1516_copy_region_block_or_regular(read_ptr_mipmap_layer, write_ptr_mipmap_layer, 0, 0, width, width, height, block_w, block_h, pitch, pixel_size, block_size);15171518RDD::BufferTextureCopyRegion copy_region;1519copy_region.buffer_offset = staging_buffer_offset;1520copy_region.texture_subresources.aspect = texture->read_aspect_flags;1521copy_region.texture_subresources.mipmap = mm_i;1522copy_region.texture_subresources.base_layer = p_layer;1523copy_region.texture_subresources.layer_count = 1;1524copy_region.texture_offset = Vector3i(0, 0, z);1525copy_region.texture_region_size = Vector3i(logic_width, logic_height, 1);1526driver->command_copy_buffer_to_texture(transfer_worker->command_buffer, transfer_worker->staging_buffer, texture->driver_id, p_dst_layout, copy_region);1527}15281529staging_local_offset += to_allocate;1530}15311532mipmap_offset = image_total;1533logic_width = MAX(1u, logic_width >> 1);1534logic_height = MAX(1u, logic_height >> 1);1535}15361537if (copy_pass) {1538driver->buffer_unmap(transfer_worker->staging_buffer);15391540// If the texture does not have a tracker, it means it must be transitioned to the sampling state.1541if (texture->draw_tracker == nullptr && driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) {1542RDD::TextureBarrier tb;1543tb.texture = texture->driver_id;1544tb.src_access = RDD::BARRIER_ACCESS_COPY_WRITE_BIT;1545tb.prev_layout = p_dst_layout;1546tb.next_layout = RDD::TEXTURE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;1547tb.subresources.aspect = texture->barrier_aspect_flags;1548tb.subresources.mipmap_count = texture->mipmaps;1549tb.subresources.base_layer = p_layer;1550tb.subresources.layer_count = 1;1551transfer_worker->texture_barriers.push_back(tb);1552}15531554if (p_immediate_flush) {1555_end_transfer_worker(transfer_worker);1556_submit_transfer_worker(transfer_worker);1557_wait_for_transfer_worker(transfer_worker);1558}15591560_release_transfer_worker(transfer_worker);1561}1562}15631564return OK;1565}15661567Error RenderingDevice::texture_update(RID p_texture, uint32_t p_layer, const Vector<uint8_t> &p_data) {1568ERR_RENDER_THREAD_GUARD_V(ERR_UNAVAILABLE);15691570ERR_FAIL_COND_V_MSG(draw_list.active || compute_list.active, ERR_INVALID_PARAMETER, "Updating textures is forbidden during creation of a draw or compute list");15711572Texture *texture = texture_owner.get_or_null(p_texture);1573ERR_FAIL_NULL_V(texture, ERR_INVALID_PARAMETER);15741575if (texture->owner != RID()) {1576p_texture = texture->owner;1577texture = texture_owner.get_or_null(texture->owner);1578ERR_FAIL_NULL_V(texture, ERR_BUG); // This is a bug.1579}15801581ERR_FAIL_COND_V_MSG(texture->bound, ERR_CANT_ACQUIRE_RESOURCE,1582"Texture can't be updated while a draw list that uses it as part of a framebuffer is being created. Ensure the draw list is finalized (and that the color/depth texture using it is not set to `RenderingDevice.FINAL_ACTION_CONTINUE`) to update this texture.");15831584ERR_FAIL_COND_V_MSG(!(texture->usage_flags & TEXTURE_USAGE_CAN_UPDATE_BIT), ERR_INVALID_PARAMETER, "Texture requires the `RenderingDevice.TEXTURE_USAGE_CAN_UPDATE_BIT` to be set to be updatable.");15851586uint32_t layer_count = _texture_layer_count(texture);1587ERR_FAIL_COND_V(p_layer >= layer_count, ERR_INVALID_PARAMETER);15881589uint32_t width, height;1590uint32_t tight_mip_size = get_image_format_required_size(texture->format, texture->width, texture->height, texture->depth, texture->mipmaps, &width, &height);1591uint32_t required_size = tight_mip_size;1592uint32_t required_align = _texture_alignment(texture);15931594ERR_FAIL_COND_V_MSG(required_size != (uint32_t)p_data.size(), ERR_INVALID_PARAMETER,1595"Required size for texture update (" + itos(required_size) + ") does not match data supplied size (" + itos(p_data.size()) + ").");15961597_check_transfer_worker_texture(texture);15981599uint32_t block_w, block_h;1600get_compressed_image_format_block_dimensions(texture->format, block_w, block_h);16011602uint32_t pixel_size = get_image_format_pixel_size(texture->format);1603uint32_t pixel_rshift = get_compressed_image_format_pixel_rshift(texture->format);1604uint32_t block_size = get_compressed_image_format_block_byte_size(texture->format);16051606uint32_t region_size = texture_upload_region_size_px;16071608const uint8_t *read_ptr = p_data.ptr();16091610thread_local LocalVector<RDG::RecordedBufferToTextureCopy> command_buffer_to_texture_copies_vector;1611command_buffer_to_texture_copies_vector.clear();16121613// Indicate the texture will get modified for the shared texture fallback.1614_texture_update_shared_fallback(p_texture, texture, true);16151616uint32_t mipmap_offset = 0;16171618uint32_t logic_width = texture->width;1619uint32_t logic_height = texture->height;16201621for (uint32_t mm_i = 0; mm_i < texture->mipmaps; mm_i++) {1622uint32_t depth = 0;1623uint32_t image_total = get_image_format_required_size(texture->format, texture->width, texture->height, texture->depth, mm_i + 1, &width, &height, &depth);16241625const uint8_t *read_ptr_mipmap = read_ptr + mipmap_offset;1626tight_mip_size = image_total - mipmap_offset;16271628for (uint32_t z = 0; z < depth; z++) {1629const uint8_t *read_ptr_mipmap_layer = read_ptr_mipmap + (tight_mip_size / depth) * z;1630for (uint32_t y = 0; y < height; y += region_size) {1631for (uint32_t x = 0; x < width; x += region_size) {1632uint32_t region_w = MIN(region_size, width - x);1633uint32_t region_h = MIN(region_size, height - y);16341635uint32_t region_logic_w = MIN(region_size, logic_width - x);1636uint32_t region_logic_h = MIN(region_size, logic_height - y);16371638uint32_t region_pitch = (region_w * pixel_size * block_w) >> pixel_rshift;1639uint32_t pitch_step = driver->api_trait_get(RDD::API_TRAIT_TEXTURE_DATA_ROW_PITCH_STEP);1640region_pitch = STEPIFY(region_pitch, pitch_step);1641uint32_t to_allocate = region_pitch * region_h;1642uint32_t alloc_offset = 0, alloc_size = 0;1643StagingRequiredAction required_action;1644Error err = _staging_buffer_allocate(upload_staging_buffers, to_allocate, required_align, alloc_offset, alloc_size, required_action, false);1645ERR_FAIL_COND_V(err, ERR_CANT_CREATE);16461647if (!command_buffer_to_texture_copies_vector.is_empty() && required_action == STAGING_REQUIRED_ACTION_FLUSH_AND_STALL_ALL) {1648if (_texture_make_mutable(texture, p_texture)) {1649// The texture must be mutable to be used as a copy destination.1650draw_graph.add_synchronization();1651}16521653// If the staging buffer requires flushing everything, we submit the command early and clear the current vector.1654draw_graph.add_texture_update(texture->driver_id, texture->draw_tracker, command_buffer_to_texture_copies_vector);1655command_buffer_to_texture_copies_vector.clear();1656}16571658_staging_buffer_execute_required_action(upload_staging_buffers, required_action);16591660uint8_t *write_ptr;16611662{ // Map.1663uint8_t *data_ptr = driver->buffer_map(upload_staging_buffers.blocks[upload_staging_buffers.current].driver_id);1664ERR_FAIL_NULL_V(data_ptr, ERR_CANT_CREATE);1665write_ptr = data_ptr;1666write_ptr += alloc_offset;1667}16681669ERR_FAIL_COND_V(region_w % block_w, ERR_BUG);1670ERR_FAIL_COND_V(region_h % block_h, ERR_BUG);16711672_copy_region_block_or_regular(read_ptr_mipmap_layer, write_ptr, x, y, width, region_w, region_h, block_w, block_h, region_pitch, pixel_size, block_size);16731674{ // Unmap.1675driver->buffer_unmap(upload_staging_buffers.blocks[upload_staging_buffers.current].driver_id);1676}16771678RDD::BufferTextureCopyRegion copy_region;1679copy_region.buffer_offset = alloc_offset;1680copy_region.texture_subresources.aspect = texture->read_aspect_flags;1681copy_region.texture_subresources.mipmap = mm_i;1682copy_region.texture_subresources.base_layer = p_layer;1683copy_region.texture_subresources.layer_count = 1;1684copy_region.texture_offset = Vector3i(x, y, z);1685copy_region.texture_region_size = Vector3i(region_logic_w, region_logic_h, 1);16861687RDG::RecordedBufferToTextureCopy buffer_to_texture_copy;1688buffer_to_texture_copy.from_buffer = upload_staging_buffers.blocks[upload_staging_buffers.current].driver_id;1689buffer_to_texture_copy.region = copy_region;1690command_buffer_to_texture_copies_vector.push_back(buffer_to_texture_copy);16911692upload_staging_buffers.blocks.write[upload_staging_buffers.current].fill_amount = alloc_offset + alloc_size;1693}1694}1695}16961697mipmap_offset = image_total;1698logic_width = MAX(1u, logic_width >> 1);1699logic_height = MAX(1u, logic_height >> 1);1700}17011702if (_texture_make_mutable(texture, p_texture)) {1703// The texture must be mutable to be used as a copy destination.1704draw_graph.add_synchronization();1705}17061707draw_graph.add_texture_update(texture->driver_id, texture->draw_tracker, command_buffer_to_texture_copies_vector);17081709return OK;1710}17111712void RenderingDevice::_texture_check_shared_fallback(Texture *p_texture) {1713if (p_texture->shared_fallback == nullptr) {1714p_texture->shared_fallback = memnew(Texture::SharedFallback);1715}1716}17171718void RenderingDevice::_texture_update_shared_fallback(RID p_texture_rid, Texture *p_texture, bool p_for_writing) {1719if (p_texture->shared_fallback == nullptr) {1720// This texture does not use any of the shared texture fallbacks.1721return;1722}17231724if (p_texture->owner.is_valid()) {1725Texture *owner_texture = texture_owner.get_or_null(p_texture->owner);1726ERR_FAIL_NULL(owner_texture);1727if (p_for_writing) {1728// Only the main texture is used for writing when using the shared fallback.1729owner_texture->shared_fallback->revision++;1730} else if (p_texture->shared_fallback->revision != owner_texture->shared_fallback->revision) {1731// Copy the contents of the main texture into the shared texture fallback slice. Update the revision.1732_texture_copy_shared(p_texture->owner, owner_texture, p_texture_rid, p_texture);1733p_texture->shared_fallback->revision = owner_texture->shared_fallback->revision;1734}1735} else if (p_for_writing) {1736// Increment the revision of the texture so shared texture fallback slices must be updated.1737p_texture->shared_fallback->revision++;1738}1739}17401741void RenderingDevice::_texture_free_shared_fallback(Texture *p_texture) {1742if (p_texture->shared_fallback != nullptr) {1743if (p_texture->shared_fallback->texture_tracker != nullptr) {1744RDG::resource_tracker_free(p_texture->shared_fallback->texture_tracker);1745}17461747if (p_texture->shared_fallback->buffer_tracker != nullptr) {1748RDG::resource_tracker_free(p_texture->shared_fallback->buffer_tracker);1749}17501751if (p_texture->shared_fallback->texture.id != 0) {1752texture_memory -= driver->texture_get_allocation_size(p_texture->shared_fallback->texture);1753driver->texture_free(p_texture->shared_fallback->texture);1754}17551756if (p_texture->shared_fallback->buffer.id != 0) {1757buffer_memory -= driver->buffer_get_allocation_size(p_texture->shared_fallback->buffer);1758driver->buffer_free(p_texture->shared_fallback->buffer);1759}17601761memdelete(p_texture->shared_fallback);1762p_texture->shared_fallback = nullptr;1763}1764}17651766void RenderingDevice::_texture_copy_shared(RID p_src_texture_rid, Texture *p_src_texture, RID p_dst_texture_rid, Texture *p_dst_texture) {1767// The only type of copying allowed is from the main texture to the slice texture, as slice textures are not allowed to be used for writing when using this fallback.1768DEV_ASSERT(p_src_texture != nullptr);1769DEV_ASSERT(p_dst_texture != nullptr);1770DEV_ASSERT(p_src_texture->owner.is_null());1771DEV_ASSERT(p_dst_texture->owner == p_src_texture_rid);17721773bool src_made_mutable = _texture_make_mutable(p_src_texture, p_src_texture_rid);1774bool dst_made_mutable = _texture_make_mutable(p_dst_texture, p_dst_texture_rid);1775if (src_made_mutable || dst_made_mutable) {1776draw_graph.add_synchronization();1777}17781779if (p_dst_texture->shared_fallback->raw_reinterpretation) {1780// If one of the textures is a main texture and they have a reinterpret buffer, we prefer using that as it's guaranteed to be big enough to hold1781// anything and it's how the shared textures that don't use slices are created.1782bool src_has_buffer = p_src_texture->shared_fallback->buffer.id != 0;1783bool dst_has_buffer = p_dst_texture->shared_fallback->buffer.id != 0;1784bool from_src = p_src_texture->owner.is_null() && src_has_buffer;1785bool from_dst = p_dst_texture->owner.is_null() && dst_has_buffer;1786if (!from_src && !from_dst) {1787// If neither texture passed the condition, we just pick whichever texture has a reinterpretation buffer.1788from_src = src_has_buffer;1789from_dst = dst_has_buffer;1790}17911792// Pick the buffer and tracker to use from the right texture.1793RDD::BufferID shared_buffer;1794RDG::ResourceTracker *shared_buffer_tracker = nullptr;1795if (from_src) {1796shared_buffer = p_src_texture->shared_fallback->buffer;1797shared_buffer_tracker = p_src_texture->shared_fallback->buffer_tracker;1798} else if (from_dst) {1799shared_buffer = p_dst_texture->shared_fallback->buffer;1800shared_buffer_tracker = p_dst_texture->shared_fallback->buffer_tracker;1801} else {1802DEV_ASSERT(false && "This path should not be reachable.");1803}18041805// FIXME: When using reinterpretation buffers, the only texture aspect supported is color. Depth or stencil contents won't get copied.1806RDD::BufferTextureCopyRegion get_data_region;1807RDG::RecordedBufferToTextureCopy update_copy;1808RDD::TextureCopyableLayout first_copyable_layout;1809RDD::TextureCopyableLayout copyable_layout;1810RDD::TextureSubresource texture_subresource;1811texture_subresource.aspect = RDD::TEXTURE_ASPECT_COLOR;1812texture_subresource.layer = 0;1813texture_subresource.mipmap = 0;1814driver->texture_get_copyable_layout(p_dst_texture->shared_fallback->texture, texture_subresource, &first_copyable_layout);18151816// Copying each mipmap from main texture to a buffer and then to the slice texture.1817thread_local LocalVector<RDD::BufferTextureCopyRegion> get_data_vector;1818thread_local LocalVector<RDG::RecordedBufferToTextureCopy> update_vector;1819get_data_vector.clear();1820update_vector.clear();1821for (uint32_t i = 0; i < p_dst_texture->mipmaps; i++) {1822driver->texture_get_copyable_layout(p_dst_texture->shared_fallback->texture, texture_subresource, ©able_layout);18231824uint32_t mipmap = p_dst_texture->base_mipmap + i;1825get_data_region.buffer_offset = copyable_layout.offset - first_copyable_layout.offset;1826get_data_region.texture_subresources.aspect = RDD::TEXTURE_ASPECT_COLOR_BIT;1827get_data_region.texture_subresources.base_layer = p_dst_texture->base_layer;1828get_data_region.texture_subresources.mipmap = mipmap;1829get_data_region.texture_subresources.layer_count = p_dst_texture->layers;1830get_data_region.texture_region_size.x = MAX(1U, p_src_texture->width >> mipmap);1831get_data_region.texture_region_size.y = MAX(1U, p_src_texture->height >> mipmap);1832get_data_region.texture_region_size.z = MAX(1U, p_src_texture->depth >> mipmap);1833get_data_vector.push_back(get_data_region);18341835update_copy.from_buffer = shared_buffer;1836update_copy.region.buffer_offset = get_data_region.buffer_offset;1837update_copy.region.texture_subresources.aspect = RDD::TEXTURE_ASPECT_COLOR_BIT;1838update_copy.region.texture_subresources.base_layer = texture_subresource.layer;1839update_copy.region.texture_subresources.mipmap = texture_subresource.mipmap;1840update_copy.region.texture_subresources.layer_count = get_data_region.texture_subresources.layer_count;1841update_copy.region.texture_region_size.x = get_data_region.texture_region_size.x;1842update_copy.region.texture_region_size.y = get_data_region.texture_region_size.y;1843update_copy.region.texture_region_size.z = get_data_region.texture_region_size.z;1844update_vector.push_back(update_copy);18451846texture_subresource.mipmap++;1847}18481849draw_graph.add_texture_get_data(p_src_texture->driver_id, p_src_texture->draw_tracker, shared_buffer, get_data_vector, shared_buffer_tracker);1850draw_graph.add_texture_update(p_dst_texture->shared_fallback->texture, p_dst_texture->shared_fallback->texture_tracker, update_vector, shared_buffer_tracker);1851} else {1852// Raw reinterpretation is not required. Use a regular texture copy.1853RDD::TextureCopyRegion copy_region;1854copy_region.src_subresources.aspect = p_src_texture->read_aspect_flags;1855copy_region.src_subresources.base_layer = p_dst_texture->base_layer;1856copy_region.src_subresources.layer_count = p_dst_texture->layers;1857copy_region.dst_subresources.aspect = p_dst_texture->read_aspect_flags;1858copy_region.dst_subresources.base_layer = 0;1859copy_region.dst_subresources.layer_count = copy_region.src_subresources.layer_count;18601861// Copying each mipmap from main texture to to the slice texture.1862thread_local LocalVector<RDD::TextureCopyRegion> region_vector;1863region_vector.clear();1864for (uint32_t i = 0; i < p_dst_texture->mipmaps; i++) {1865uint32_t mipmap = p_dst_texture->base_mipmap + i;1866copy_region.src_subresources.mipmap = mipmap;1867copy_region.dst_subresources.mipmap = i;1868copy_region.size.x = MAX(1U, p_src_texture->width >> mipmap);1869copy_region.size.y = MAX(1U, p_src_texture->height >> mipmap);1870copy_region.size.z = MAX(1U, p_src_texture->depth >> mipmap);1871region_vector.push_back(copy_region);1872}18731874draw_graph.add_texture_copy(p_src_texture->driver_id, p_src_texture->draw_tracker, p_dst_texture->shared_fallback->texture, p_dst_texture->shared_fallback->texture_tracker, region_vector);1875}1876}18771878void RenderingDevice::_texture_create_reinterpret_buffer(Texture *p_texture) {1879uint64_t row_pitch_step = driver->api_trait_get(RDD::API_TRAIT_TEXTURE_DATA_ROW_PITCH_STEP);1880uint64_t transfer_alignment = driver->api_trait_get(RDD::API_TRAIT_TEXTURE_TRANSFER_ALIGNMENT);1881uint32_t pixel_bytes = get_image_format_pixel_size(p_texture->format);1882uint32_t row_pitch = STEPIFY(p_texture->width * pixel_bytes, row_pitch_step);1883uint64_t buffer_size = STEPIFY(pixel_bytes * row_pitch * p_texture->height * p_texture->depth, transfer_alignment);1884p_texture->shared_fallback->buffer = driver->buffer_create(buffer_size, RDD::BUFFER_USAGE_TRANSFER_FROM_BIT | RDD::BUFFER_USAGE_TRANSFER_TO_BIT, RDD::MEMORY_ALLOCATION_TYPE_GPU);1885buffer_memory += driver->buffer_get_allocation_size(p_texture->shared_fallback->buffer);18861887RDG::ResourceTracker *tracker = RDG::resource_tracker_create();1888tracker->buffer_driver_id = p_texture->shared_fallback->buffer;1889p_texture->shared_fallback->buffer_tracker = tracker;1890}18911892uint32_t RenderingDevice::_texture_vrs_method_to_usage_bits() const {1893switch (vrs_method) {1894case VRS_METHOD_FRAGMENT_SHADING_RATE:1895return RDD::TEXTURE_USAGE_VRS_FRAGMENT_SHADING_RATE_BIT;1896case VRS_METHOD_FRAGMENT_DENSITY_MAP:1897return RDD::TEXTURE_USAGE_VRS_FRAGMENT_DENSITY_MAP_BIT;1898default:1899return 0;1900}1901}19021903Vector<uint8_t> RenderingDevice::_texture_get_data(Texture *tex, uint32_t p_layer, bool p_2d) {1904uint32_t width, height, depth;1905uint32_t tight_mip_size = get_image_format_required_size(tex->format, tex->width, tex->height, p_2d ? 1 : tex->depth, tex->mipmaps, &width, &height, &depth);19061907Vector<uint8_t> image_data;1908image_data.resize(tight_mip_size);19091910uint32_t blockw, blockh;1911get_compressed_image_format_block_dimensions(tex->format, blockw, blockh);1912uint32_t block_size = get_compressed_image_format_block_byte_size(tex->format);1913uint32_t pixel_size = get_image_format_pixel_size(tex->format);19141915{1916uint8_t *w = image_data.ptrw();19171918uint32_t mipmap_offset = 0;1919for (uint32_t mm_i = 0; mm_i < tex->mipmaps; mm_i++) {1920uint32_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);19211922uint8_t *write_ptr_mipmap = w + mipmap_offset;1923tight_mip_size = image_total - mipmap_offset;19241925RDD::TextureSubresource subres;1926subres.aspect = RDD::TEXTURE_ASPECT_COLOR;1927subres.layer = p_layer;1928subres.mipmap = mm_i;1929RDD::TextureCopyableLayout layout;1930driver->texture_get_copyable_layout(tex->driver_id, subres, &layout);19311932uint8_t *img_mem = driver->texture_map(tex->driver_id, subres);1933ERR_FAIL_NULL_V(img_mem, Vector<uint8_t>());19341935for (uint32_t z = 0; z < depth; z++) {1936uint8_t *write_ptr = write_ptr_mipmap + z * tight_mip_size / depth;1937const uint8_t *slice_read_ptr = img_mem + z * layout.depth_pitch;19381939if (block_size > 1) {1940// Compressed.1941uint32_t line_width = (block_size * (width / blockw));1942for (uint32_t y = 0; y < height / blockh; y++) {1943const uint8_t *rptr = slice_read_ptr + y * layout.row_pitch;1944uint8_t *wptr = write_ptr + y * line_width;19451946memcpy(wptr, rptr, line_width);1947}19481949} else {1950// Uncompressed.1951for (uint32_t y = 0; y < height; y++) {1952const uint8_t *rptr = slice_read_ptr + y * layout.row_pitch;1953uint8_t *wptr = write_ptr + y * pixel_size * width;1954memcpy(wptr, rptr, (uint64_t)pixel_size * width);1955}1956}1957}19581959driver->texture_unmap(tex->driver_id);19601961mipmap_offset = image_total;1962}1963}19641965return image_data;1966}19671968Vector<uint8_t> RenderingDevice::texture_get_data(RID p_texture, uint32_t p_layer) {1969ERR_RENDER_THREAD_GUARD_V(Vector<uint8_t>());19701971Texture *tex = texture_owner.get_or_null(p_texture);1972ERR_FAIL_NULL_V(tex, Vector<uint8_t>());19731974ERR_FAIL_COND_V_MSG(tex->bound, Vector<uint8_t>(),1975"Texture can't be retrieved while a draw list that uses it as part of a framebuffer is being created. Ensure the draw list is finalized (and that the color/depth texture using it is not set to `RenderingDevice.FINAL_ACTION_CONTINUE`) to retrieve this texture.");1976ERR_FAIL_COND_V_MSG(!(tex->usage_flags & TEXTURE_USAGE_CAN_COPY_FROM_BIT), Vector<uint8_t>(),1977"Texture requires the `RenderingDevice.TEXTURE_USAGE_CAN_COPY_FROM_BIT` to be set to be retrieved.");19781979ERR_FAIL_COND_V(p_layer >= tex->layers, Vector<uint8_t>());19801981_check_transfer_worker_texture(tex);19821983if (tex->usage_flags & TEXTURE_USAGE_CPU_READ_BIT) {1984// Does not need anything fancy, map and read.1985return _texture_get_data(tex, p_layer);1986} else {1987LocalVector<RDD::TextureCopyableLayout> mip_layouts;1988uint32_t work_mip_alignment = driver->api_trait_get(RDD::API_TRAIT_TEXTURE_TRANSFER_ALIGNMENT);1989uint32_t work_buffer_size = 0;1990mip_layouts.resize(tex->mipmaps);1991for (uint32_t i = 0; i < tex->mipmaps; i++) {1992RDD::TextureSubresource subres;1993subres.aspect = RDD::TEXTURE_ASPECT_COLOR;1994subres.layer = p_layer;1995subres.mipmap = i;1996driver->texture_get_copyable_layout(tex->driver_id, subres, &mip_layouts[i]);19971998// Assuming layers are tightly packed. If this is not true on some driver, we must modify the copy algorithm.1999DEV_ASSERT(mip_layouts[i].layer_pitch == mip_layouts[i].size / tex->layers);20002001work_buffer_size = STEPIFY(work_buffer_size, work_mip_alignment) + mip_layouts[i].size;2002}20032004RDD::BufferID tmp_buffer = driver->buffer_create(work_buffer_size, RDD::BUFFER_USAGE_TRANSFER_TO_BIT, RDD::MEMORY_ALLOCATION_TYPE_CPU);2005ERR_FAIL_COND_V(!tmp_buffer, Vector<uint8_t>());20062007thread_local LocalVector<RDD::BufferTextureCopyRegion> command_buffer_texture_copy_regions_vector;2008command_buffer_texture_copy_regions_vector.clear();20092010uint32_t w = tex->width;2011uint32_t h = tex->height;2012uint32_t d = tex->depth;2013for (uint32_t i = 0; i < tex->mipmaps; i++) {2014RDD::BufferTextureCopyRegion copy_region;2015copy_region.buffer_offset = mip_layouts[i].offset;2016copy_region.texture_subresources.aspect = tex->read_aspect_flags;2017copy_region.texture_subresources.mipmap = i;2018copy_region.texture_subresources.base_layer = p_layer;2019copy_region.texture_subresources.layer_count = 1;2020copy_region.texture_region_size.x = w;2021copy_region.texture_region_size.y = h;2022copy_region.texture_region_size.z = d;2023command_buffer_texture_copy_regions_vector.push_back(copy_region);20242025w = MAX(1u, w >> 1);2026h = MAX(1u, h >> 1);2027d = MAX(1u, d >> 1);2028}20292030if (_texture_make_mutable(tex, p_texture)) {2031// The texture must be mutable to be used as a copy source due to layout transitions.2032draw_graph.add_synchronization();2033}20342035draw_graph.add_texture_get_data(tex->driver_id, tex->draw_tracker, tmp_buffer, command_buffer_texture_copy_regions_vector);20362037// Flush everything so memory can be safely mapped.2038_flush_and_stall_for_all_frames();20392040const uint8_t *read_ptr = driver->buffer_map(tmp_buffer);2041ERR_FAIL_NULL_V(read_ptr, Vector<uint8_t>());20422043uint32_t block_w = 0;2044uint32_t block_h = 0;2045get_compressed_image_format_block_dimensions(tex->format, block_w, block_h);20462047Vector<uint8_t> buffer_data;2048uint32_t tight_buffer_size = get_image_format_required_size(tex->format, tex->width, tex->height, tex->depth, tex->mipmaps);2049buffer_data.resize(tight_buffer_size);20502051uint8_t *write_ptr = buffer_data.ptrw();20522053w = tex->width;2054h = tex->height;2055d = tex->depth;2056for (uint32_t i = 0; i < tex->mipmaps; i++) {2057uint32_t width = 0, height = 0, depth = 0;2058uint32_t tight_mip_size = get_image_format_required_size(tex->format, w, h, d, 1, &width, &height, &depth);2059uint32_t tight_row_pitch = tight_mip_size / ((height / block_h) * depth);20602061// Copy row-by-row to erase padding due to alignments.2062const uint8_t *rp = read_ptr;2063uint8_t *wp = write_ptr;2064for (uint32_t row = h * d / block_h; row != 0; row--) {2065memcpy(wp, rp, tight_row_pitch);2066rp += mip_layouts[i].row_pitch;2067wp += tight_row_pitch;2068}20692070w = MAX(block_w, w >> 1);2071h = MAX(block_h, h >> 1);2072d = MAX(1u, d >> 1);2073read_ptr += mip_layouts[i].size;2074write_ptr += tight_mip_size;2075}20762077driver->buffer_unmap(tmp_buffer);2078driver->buffer_free(tmp_buffer);20792080return buffer_data;2081}2082}20832084Error RenderingDevice::texture_get_data_async(RID p_texture, uint32_t p_layer, const Callable &p_callback) {2085ERR_RENDER_THREAD_GUARD_V(ERR_UNAVAILABLE);20862087Texture *tex = texture_owner.get_or_null(p_texture);2088ERR_FAIL_NULL_V(tex, ERR_INVALID_PARAMETER);20892090ERR_FAIL_COND_V_MSG(tex->bound, ERR_INVALID_PARAMETER, "Texture can't be retrieved while a draw list that uses it as part of a framebuffer is being created. Ensure the draw list is finalized (and that the color/depth texture using it is not set to `RenderingDevice.FINAL_ACTION_CONTINUE`) to retrieve this texture.");2091ERR_FAIL_COND_V_MSG(!(tex->usage_flags & TEXTURE_USAGE_CAN_COPY_FROM_BIT), ERR_INVALID_PARAMETER, "Texture requires the `RenderingDevice.TEXTURE_USAGE_CAN_COPY_FROM_BIT` to be set to be retrieved.");2092ERR_FAIL_COND_V(p_layer >= tex->layers, ERR_INVALID_PARAMETER);20932094_check_transfer_worker_texture(tex);20952096thread_local LocalVector<RDD::TextureCopyableLayout> mip_layouts;2097mip_layouts.resize(tex->mipmaps);2098for (uint32_t i = 0; i < tex->mipmaps; i++) {2099RDD::TextureSubresource subres;2100subres.aspect = RDD::TEXTURE_ASPECT_COLOR;2101subres.layer = p_layer;2102subres.mipmap = i;2103driver->texture_get_copyable_layout(tex->driver_id, subres, &mip_layouts[i]);21042105// Assuming layers are tightly packed. If this is not true on some driver, we must modify the copy algorithm.2106DEV_ASSERT(mip_layouts[i].layer_pitch == mip_layouts[i].size / tex->layers);2107}21082109ERR_FAIL_COND_V(mip_layouts.is_empty(), ERR_INVALID_PARAMETER);21102111if (_texture_make_mutable(tex, p_texture)) {2112// The texture must be mutable to be used as a copy source due to layout transitions.2113draw_graph.add_synchronization();2114}21152116TextureGetDataRequest get_data_request;2117get_data_request.callback = p_callback;2118get_data_request.frame_local_index = frames[frame].download_buffer_texture_copy_regions.size();2119get_data_request.width = tex->width;2120get_data_request.height = tex->height;2121get_data_request.depth = tex->depth;2122get_data_request.format = tex->format;2123get_data_request.mipmaps = tex->mipmaps;21242125uint32_t block_w, block_h;2126get_compressed_image_format_block_dimensions(tex->format, block_w, block_h);21272128uint32_t pixel_size = get_image_format_pixel_size(tex->format);2129uint32_t pixel_rshift = get_compressed_image_format_pixel_rshift(tex->format);21302131uint32_t w, h, d;2132uint32_t required_align = driver->api_trait_get(RDD::API_TRAIT_TEXTURE_TRANSFER_ALIGNMENT);2133uint32_t pitch_step = driver->api_trait_get(RDD::API_TRAIT_TEXTURE_DATA_ROW_PITCH_STEP);2134uint32_t region_size = texture_download_region_size_px;2135uint32_t logic_w = tex->width;2136uint32_t logic_h = tex->height;2137uint32_t mipmap_offset = 0;2138uint32_t block_write_offset;2139uint32_t block_write_amount;2140StagingRequiredAction required_action;2141for (uint32_t i = 0; i < tex->mipmaps; i++) {2142uint32_t image_total = get_image_format_required_size(tex->format, tex->width, tex->height, tex->depth, i + 1, &w, &h, &d);2143uint32_t tight_mip_size = image_total - mipmap_offset;2144for (uint32_t z = 0; z < d; z++) {2145for (uint32_t y = 0; y < h; y += region_size) {2146for (uint32_t x = 0; x < w; x += region_size) {2147uint32_t region_w = MIN(region_size, w - x);2148uint32_t region_h = MIN(region_size, h - y);2149ERR_FAIL_COND_V(region_w % block_w, ERR_BUG);2150ERR_FAIL_COND_V(region_h % block_h, ERR_BUG);21512152uint32_t region_logic_w = MIN(region_size, logic_w - x);2153uint32_t region_logic_h = MIN(region_size, logic_h - y);2154uint32_t region_pitch = (region_w * pixel_size * block_w) >> pixel_rshift;2155region_pitch = STEPIFY(region_pitch, pitch_step);21562157uint32_t to_allocate = region_pitch * region_h;2158Error err = _staging_buffer_allocate(download_staging_buffers, to_allocate, required_align, block_write_offset, block_write_amount, required_action, false);2159ERR_FAIL_COND_V(err, ERR_CANT_CREATE);21602161const bool flush_frames = (get_data_request.frame_local_count > 0) && required_action == STAGING_REQUIRED_ACTION_FLUSH_AND_STALL_ALL;2162if (flush_frames) {2163for (uint32_t j = 0; j < get_data_request.frame_local_count; j++) {2164uint32_t local_index = get_data_request.frame_local_index + j;2165draw_graph.add_texture_get_data(tex->driver_id, tex->draw_tracker, frames[frame].download_texture_staging_buffers[local_index], frames[frame].download_buffer_texture_copy_regions[local_index]);2166}2167}21682169_staging_buffer_execute_required_action(download_staging_buffers, required_action);21702171if (flush_frames) {2172get_data_request.frame_local_count = 0;2173get_data_request.frame_local_index = frames[frame].download_buffer_texture_copy_regions.size();2174}21752176RDD::BufferTextureCopyRegion copy_region;2177copy_region.buffer_offset = block_write_offset;2178copy_region.texture_subresources.aspect = tex->read_aspect_flags;2179copy_region.texture_subresources.mipmap = i;2180copy_region.texture_subresources.base_layer = p_layer;2181copy_region.texture_subresources.layer_count = 1;2182copy_region.texture_offset = Vector3i(x, y, z);2183copy_region.texture_region_size = Vector3i(region_logic_w, region_logic_h, 1);2184frames[frame].download_texture_staging_buffers.push_back(download_staging_buffers.blocks[download_staging_buffers.current].driver_id);2185frames[frame].download_buffer_texture_copy_regions.push_back(copy_region);2186frames[frame].download_texture_mipmap_offsets.push_back(mipmap_offset + (tight_mip_size / d) * z);2187get_data_request.frame_local_count++;21882189download_staging_buffers.blocks.write[download_staging_buffers.current].fill_amount = block_write_offset + block_write_amount;2190}2191}2192}21932194mipmap_offset = image_total;2195logic_w = MAX(1u, logic_w >> 1);2196logic_h = MAX(1u, logic_h >> 1);2197}21982199if (get_data_request.frame_local_count > 0) {2200for (uint32_t i = 0; i < get_data_request.frame_local_count; i++) {2201uint32_t local_index = get_data_request.frame_local_index + i;2202draw_graph.add_texture_get_data(tex->driver_id, tex->draw_tracker, frames[frame].download_texture_staging_buffers[local_index], frames[frame].download_buffer_texture_copy_regions[local_index]);2203}22042205frames[frame].download_texture_get_data_requests.push_back(get_data_request);2206}22072208return OK;2209}22102211bool RenderingDevice::texture_is_shared(RID p_texture) {2212ERR_RENDER_THREAD_GUARD_V(false);22132214Texture *tex = texture_owner.get_or_null(p_texture);2215ERR_FAIL_NULL_V(tex, false);2216return tex->owner.is_valid();2217}22182219bool RenderingDevice::texture_is_valid(RID p_texture) {2220ERR_RENDER_THREAD_GUARD_V(false);22212222return texture_owner.owns(p_texture);2223}22242225RD::TextureFormat RenderingDevice::texture_get_format(RID p_texture) {2226ERR_RENDER_THREAD_GUARD_V(TextureFormat());22272228Texture *tex = texture_owner.get_or_null(p_texture);2229ERR_FAIL_NULL_V(tex, TextureFormat());22302231TextureFormat tf;22322233tf.format = tex->format;2234tf.width = tex->width;2235tf.height = tex->height;2236tf.depth = tex->depth;2237tf.array_layers = tex->layers;2238tf.mipmaps = tex->mipmaps;2239tf.texture_type = tex->type;2240tf.samples = tex->samples;2241tf.usage_bits = tex->usage_flags;2242tf.shareable_formats = tex->allowed_shared_formats;2243tf.is_resolve_buffer = tex->is_resolve_buffer;2244tf.is_discardable = tex->is_discardable;22452246return tf;2247}22482249Size2i RenderingDevice::texture_size(RID p_texture) {2250ERR_RENDER_THREAD_GUARD_V(Size2i());22512252Texture *tex = texture_owner.get_or_null(p_texture);2253ERR_FAIL_NULL_V(tex, Size2i());2254return Size2i(tex->width, tex->height);2255}22562257#ifndef DISABLE_DEPRECATED2258uint64_t RenderingDevice::texture_get_native_handle(RID p_texture) {2259return get_driver_resource(DRIVER_RESOURCE_TEXTURE, p_texture);2260}2261#endif22622263Error RenderingDevice::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) {2264ERR_RENDER_THREAD_GUARD_V(ERR_UNAVAILABLE);22652266Texture *src_tex = texture_owner.get_or_null(p_from_texture);2267ERR_FAIL_NULL_V(src_tex, ERR_INVALID_PARAMETER);22682269ERR_FAIL_COND_V_MSG(src_tex->bound, ERR_INVALID_PARAMETER,2270"Source texture can't be copied while a draw list that uses it as part of a framebuffer is being created. Ensure the draw list is finalized (and that the color/depth texture using it is not set to `RenderingDevice.FINAL_ACTION_CONTINUE`) to copy this texture.");2271ERR_FAIL_COND_V_MSG(!(src_tex->usage_flags & TEXTURE_USAGE_CAN_COPY_FROM_BIT), ERR_INVALID_PARAMETER,2272"Source texture requires the `RenderingDevice.TEXTURE_USAGE_CAN_COPY_FROM_BIT` to be set to be retrieved.");22732274uint32_t src_width, src_height, src_depth;2275get_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);22762277ERR_FAIL_COND_V(p_from.x < 0 || p_from.x + p_size.x > src_width, ERR_INVALID_PARAMETER);2278ERR_FAIL_COND_V(p_from.y < 0 || p_from.y + p_size.y > src_height, ERR_INVALID_PARAMETER);2279ERR_FAIL_COND_V(p_from.z < 0 || p_from.z + p_size.z > src_depth, ERR_INVALID_PARAMETER);2280ERR_FAIL_COND_V(p_src_mipmap >= src_tex->mipmaps, ERR_INVALID_PARAMETER);2281ERR_FAIL_COND_V(p_src_layer >= src_tex->layers, ERR_INVALID_PARAMETER);22822283Texture *dst_tex = texture_owner.get_or_null(p_to_texture);2284ERR_FAIL_NULL_V(dst_tex, ERR_INVALID_PARAMETER);22852286ERR_FAIL_COND_V_MSG(dst_tex->bound, ERR_INVALID_PARAMETER,2287"Destination texture can't be copied while a draw list that uses it as part of a framebuffer is being created. Ensure the draw list is finalized (and that the color/depth texture using it is not set to `RenderingDevice.FINAL_ACTION_CONTINUE`) to copy this texture.");2288ERR_FAIL_COND_V_MSG(!(dst_tex->usage_flags & TEXTURE_USAGE_CAN_COPY_TO_BIT), ERR_INVALID_PARAMETER,2289"Destination texture requires the `RenderingDevice.TEXTURE_USAGE_CAN_COPY_TO_BIT` to be set to be retrieved.");22902291uint32_t dst_width, dst_height, dst_depth;2292get_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);22932294ERR_FAIL_COND_V(p_to.x < 0 || p_to.x + p_size.x > dst_width, ERR_INVALID_PARAMETER);2295ERR_FAIL_COND_V(p_to.y < 0 || p_to.y + p_size.y > dst_height, ERR_INVALID_PARAMETER);2296ERR_FAIL_COND_V(p_to.z < 0 || p_to.z + p_size.z > dst_depth, ERR_INVALID_PARAMETER);2297ERR_FAIL_COND_V(p_dst_mipmap >= dst_tex->mipmaps, ERR_INVALID_PARAMETER);2298ERR_FAIL_COND_V(p_dst_layer >= dst_tex->layers, ERR_INVALID_PARAMETER);22992300ERR_FAIL_COND_V_MSG(src_tex->read_aspect_flags != dst_tex->read_aspect_flags, ERR_INVALID_PARAMETER,2301"Source and destination texture must be of the same type (color or depth).");23022303_check_transfer_worker_texture(src_tex);2304_check_transfer_worker_texture(dst_tex);23052306RDD::TextureCopyRegion copy_region;2307copy_region.src_subresources.aspect = src_tex->read_aspect_flags;2308copy_region.src_subresources.mipmap = p_src_mipmap;2309copy_region.src_subresources.base_layer = p_src_layer;2310copy_region.src_subresources.layer_count = 1;2311copy_region.src_offset = p_from;23122313copy_region.dst_subresources.aspect = dst_tex->read_aspect_flags;2314copy_region.dst_subresources.mipmap = p_dst_mipmap;2315copy_region.dst_subresources.base_layer = p_dst_layer;2316copy_region.dst_subresources.layer_count = 1;2317copy_region.dst_offset = p_to;23182319copy_region.size = p_size;23202321// Indicate the texture will get modified for the shared texture fallback.2322_texture_update_shared_fallback(p_to_texture, dst_tex, true);23232324// The textures must be mutable to be used in the copy operation.2325bool src_made_mutable = _texture_make_mutable(src_tex, p_from_texture);2326bool dst_made_mutable = _texture_make_mutable(dst_tex, p_to_texture);2327if (src_made_mutable || dst_made_mutable) {2328draw_graph.add_synchronization();2329}23302331draw_graph.add_texture_copy(src_tex->driver_id, src_tex->draw_tracker, dst_tex->driver_id, dst_tex->draw_tracker, copy_region);23322333return OK;2334}23352336Error RenderingDevice::texture_resolve_multisample(RID p_from_texture, RID p_to_texture) {2337ERR_RENDER_THREAD_GUARD_V(ERR_UNAVAILABLE);23382339Texture *src_tex = texture_owner.get_or_null(p_from_texture);2340ERR_FAIL_NULL_V(src_tex, ERR_INVALID_PARAMETER);23412342ERR_FAIL_COND_V_MSG(src_tex->bound, ERR_INVALID_PARAMETER,2343"Source texture can't be copied while a draw list that uses it as part of a framebuffer is being created. Ensure the draw list is finalized (and that the color/depth texture using it is not set to `RenderingDevice.FINAL_ACTION_CONTINUE`) to copy this texture.");2344ERR_FAIL_COND_V_MSG(!(src_tex->usage_flags & TEXTURE_USAGE_CAN_COPY_FROM_BIT), ERR_INVALID_PARAMETER,2345"Source texture requires the `RenderingDevice.TEXTURE_USAGE_CAN_COPY_FROM_BIT` to be set to be retrieved.");23462347ERR_FAIL_COND_V_MSG(src_tex->type != TEXTURE_TYPE_2D, ERR_INVALID_PARAMETER, "Source texture must be 2D (or a slice of a 3D/Cube texture)");2348ERR_FAIL_COND_V_MSG(src_tex->samples == TEXTURE_SAMPLES_1, ERR_INVALID_PARAMETER, "Source texture must be multisampled.");23492350Texture *dst_tex = texture_owner.get_or_null(p_to_texture);2351ERR_FAIL_NULL_V(dst_tex, ERR_INVALID_PARAMETER);23522353ERR_FAIL_COND_V_MSG(dst_tex->bound, ERR_INVALID_PARAMETER,2354"Destination texture can't be copied while a draw list that uses it as part of a framebuffer is being created. Ensure the draw list is finalized (and that the color/depth texture using it is not set to `RenderingDevice.FINAL_ACTION_CONTINUE`) to copy this texture.");2355ERR_FAIL_COND_V_MSG(!(dst_tex->usage_flags & TEXTURE_USAGE_CAN_COPY_TO_BIT), ERR_INVALID_PARAMETER,2356"Destination texture requires the `RenderingDevice.TEXTURE_USAGE_CAN_COPY_TO_BIT` to be set to be retrieved.");23572358ERR_FAIL_COND_V_MSG(dst_tex->type != TEXTURE_TYPE_2D, ERR_INVALID_PARAMETER, "Destination texture must be 2D (or a slice of a 3D/Cube texture).");2359ERR_FAIL_COND_V_MSG(dst_tex->samples != TEXTURE_SAMPLES_1, ERR_INVALID_PARAMETER, "Destination texture must not be multisampled.");23602361ERR_FAIL_COND_V_MSG(src_tex->format != dst_tex->format, ERR_INVALID_PARAMETER, "Source and Destination textures must be the same format.");2362ERR_FAIL_COND_V_MSG(src_tex->width != dst_tex->width && src_tex->height != dst_tex->height && src_tex->depth != dst_tex->depth, ERR_INVALID_PARAMETER, "Source and Destination textures must have the same dimensions.");23632364ERR_FAIL_COND_V_MSG(src_tex->read_aspect_flags != dst_tex->read_aspect_flags, ERR_INVALID_PARAMETER,2365"Source and destination texture must be of the same type (color or depth).");23662367// Indicate the texture will get modified for the shared texture fallback.2368_texture_update_shared_fallback(p_to_texture, dst_tex, true);23692370_check_transfer_worker_texture(src_tex);2371_check_transfer_worker_texture(dst_tex);23722373// The textures must be mutable to be used in the resolve operation.2374bool src_made_mutable = _texture_make_mutable(src_tex, p_from_texture);2375bool dst_made_mutable = _texture_make_mutable(dst_tex, p_to_texture);2376if (src_made_mutable || dst_made_mutable) {2377draw_graph.add_synchronization();2378}23792380draw_graph.add_texture_resolve(src_tex->driver_id, src_tex->draw_tracker, dst_tex->driver_id, dst_tex->draw_tracker, src_tex->base_layer, src_tex->base_mipmap, dst_tex->base_layer, dst_tex->base_mipmap);23812382return OK;2383}23842385void RenderingDevice::texture_set_discardable(RID p_texture, bool p_discardable) {2386ERR_RENDER_THREAD_GUARD();23872388Texture *texture = texture_owner.get_or_null(p_texture);2389ERR_FAIL_NULL(texture);23902391texture->is_discardable = p_discardable;23922393if (texture->draw_tracker != nullptr) {2394texture->draw_tracker->is_discardable = p_discardable;2395}23962397if (texture->shared_fallback != nullptr && texture->shared_fallback->texture_tracker != nullptr) {2398texture->shared_fallback->texture_tracker->is_discardable = p_discardable;2399}2400}24012402bool RenderingDevice::texture_is_discardable(RID p_texture) {2403ERR_RENDER_THREAD_GUARD_V(false);24042405Texture *texture = texture_owner.get_or_null(p_texture);2406ERR_FAIL_NULL_V(texture, false);24072408return texture->is_discardable;2409}24102411Error RenderingDevice::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) {2412ERR_RENDER_THREAD_GUARD_V(ERR_UNAVAILABLE);24132414Texture *src_tex = texture_owner.get_or_null(p_texture);2415ERR_FAIL_NULL_V(src_tex, ERR_INVALID_PARAMETER);24162417ERR_FAIL_COND_V_MSG(src_tex->bound, ERR_INVALID_PARAMETER,2418"Source texture can't be cleared while a draw list that uses it as part of a framebuffer is being created. Ensure the draw list is finalized (and that the color/depth texture using it is not set to `RenderingDevice.FINAL_ACTION_CONTINUE`) to clear this texture.");24192420ERR_FAIL_COND_V(p_layers == 0, ERR_INVALID_PARAMETER);2421ERR_FAIL_COND_V(p_mipmaps == 0, ERR_INVALID_PARAMETER);24222423ERR_FAIL_COND_V_MSG(!(src_tex->usage_flags & TEXTURE_USAGE_CAN_COPY_TO_BIT), ERR_INVALID_PARAMETER,2424"Source texture requires the `RenderingDevice.TEXTURE_USAGE_CAN_COPY_TO_BIT` to be set to be cleared.");24252426ERR_FAIL_COND_V(p_base_mipmap + p_mipmaps > src_tex->mipmaps, ERR_INVALID_PARAMETER);2427ERR_FAIL_COND_V(p_base_layer + p_layers > src_tex->layers, ERR_INVALID_PARAMETER);24282429_check_transfer_worker_texture(src_tex);24302431RDD::TextureSubresourceRange range;2432range.aspect = src_tex->read_aspect_flags;2433range.base_mipmap = src_tex->base_mipmap + p_base_mipmap;2434range.mipmap_count = p_mipmaps;2435range.base_layer = src_tex->base_layer + p_base_layer;2436range.layer_count = p_layers;24372438// Indicate the texture will get modified for the shared texture fallback.2439_texture_update_shared_fallback(p_texture, src_tex, true);24402441if (_texture_make_mutable(src_tex, p_texture)) {2442// The texture must be mutable to be used as a clear destination.2443draw_graph.add_synchronization();2444}24452446draw_graph.add_texture_clear(src_tex->driver_id, src_tex->draw_tracker, p_color, range);24472448return OK;2449}24502451bool RenderingDevice::texture_is_format_supported_for_usage(DataFormat p_format, BitField<RenderingDevice::TextureUsageBits> p_usage) const {2452ERR_FAIL_INDEX_V(p_format, DATA_FORMAT_MAX, false);24532454bool cpu_readable = (p_usage & RDD::TEXTURE_USAGE_CPU_READ_BIT);2455BitField<TextureUsageBits> supported = driver->texture_get_usages_supported_by_format(p_format, cpu_readable);2456bool any_unsupported = (((int64_t)supported) | ((int64_t)p_usage)) != ((int64_t)supported);2457return !any_unsupported;2458}24592460/*********************/2461/**** FRAMEBUFFER ****/2462/*********************/24632464RDD::RenderPassID RenderingDevice::_render_pass_create(RenderingDeviceDriver *p_driver, const Vector<AttachmentFormat> &p_attachments, const Vector<FramebufferPass> &p_passes, VectorView<RDD::AttachmentLoadOp> p_load_ops, VectorView<RDD::AttachmentStoreOp> p_store_ops, uint32_t p_view_count, VRSMethod p_vrs_method, int32_t p_vrs_attachment, Size2i p_vrs_texel_size, Vector<TextureSamples> *r_samples) {2465// NOTE:2466// Before the refactor to RenderingDevice-RenderingDeviceDriver, there was commented out code to2467// specify dependencies to external subpasses. Since it had been unused for a long timel it wasn't ported2468// to the new architecture.24692470LocalVector<int32_t> attachment_last_pass;2471attachment_last_pass.resize(p_attachments.size());24722473if (p_view_count > 1) {2474const RDD::MultiviewCapabilities &capabilities = p_driver->get_multiview_capabilities();24752476// This only works with multiview!2477ERR_FAIL_COND_V_MSG(!capabilities.is_supported, RDD::RenderPassID(), "Multiview not supported");24782479// Make sure we limit this to the number of views we support.2480ERR_FAIL_COND_V_MSG(p_view_count > capabilities.max_view_count, RDD::RenderPassID(), "Hardware does not support requested number of views for Multiview render pass");2481}24822483LocalVector<RDD::Attachment> attachments;2484LocalVector<uint32_t> attachment_remap;24852486for (int i = 0; i < p_attachments.size(); i++) {2487if (p_attachments[i].usage_flags == AttachmentFormat::UNUSED_ATTACHMENT) {2488attachment_remap.push_back(RDD::AttachmentReference::UNUSED);2489continue;2490}24912492ERR_FAIL_INDEX_V(p_attachments[i].format, DATA_FORMAT_MAX, RDD::RenderPassID());2493ERR_FAIL_INDEX_V(p_attachments[i].samples, TEXTURE_SAMPLES_MAX, RDD::RenderPassID());2494ERR_FAIL_COND_V_MSG(!(p_attachments[i].usage_flags & (TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | TEXTURE_USAGE_INPUT_ATTACHMENT_BIT | TEXTURE_USAGE_VRS_ATTACHMENT_BIT)),2495RDD::RenderPassID(), "Texture format for index (" + itos(i) + ") requires an attachment (color, depth-stencil, input or VRS) bit set.");24962497RDD::Attachment description;2498description.format = p_attachments[i].format;2499description.samples = p_attachments[i].samples;25002501// We can setup a framebuffer where we write to our VRS texture to set it up.2502// We make the assumption here that if our texture is actually used as our VRS attachment.2503// It is used as such for each subpass. This is fairly certain seeing the restrictions on subpasses.2504bool is_vrs = (p_attachments[i].usage_flags & TEXTURE_USAGE_VRS_ATTACHMENT_BIT) && i == p_vrs_attachment;2505if (is_vrs) {2506description.load_op = RDD::ATTACHMENT_LOAD_OP_LOAD;2507description.store_op = RDD::ATTACHMENT_STORE_OP_DONT_CARE;2508description.stencil_load_op = RDD::ATTACHMENT_LOAD_OP_DONT_CARE;2509description.stencil_store_op = RDD::ATTACHMENT_STORE_OP_DONT_CARE;2510description.initial_layout = _vrs_layout_from_method(p_vrs_method);2511description.final_layout = _vrs_layout_from_method(p_vrs_method);2512} else {2513if (p_attachments[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) {2514description.load_op = p_load_ops[i];2515description.store_op = p_store_ops[i];2516description.stencil_load_op = RDD::ATTACHMENT_LOAD_OP_DONT_CARE;2517description.stencil_store_op = RDD::ATTACHMENT_STORE_OP_DONT_CARE;2518description.initial_layout = RDD::TEXTURE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;2519description.final_layout = RDD::TEXTURE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;2520} else if (p_attachments[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {2521description.load_op = p_load_ops[i];2522description.store_op = p_store_ops[i];2523description.stencil_load_op = p_load_ops[i];2524description.stencil_store_op = p_store_ops[i];2525description.initial_layout = RDD::TEXTURE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;2526description.final_layout = RDD::TEXTURE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;2527} else {2528description.load_op = RDD::ATTACHMENT_LOAD_OP_DONT_CARE;2529description.store_op = RDD::ATTACHMENT_STORE_OP_DONT_CARE;2530description.stencil_load_op = RDD::ATTACHMENT_LOAD_OP_DONT_CARE;2531description.stencil_store_op = RDD::ATTACHMENT_STORE_OP_DONT_CARE;2532description.initial_layout = RDD::TEXTURE_LAYOUT_UNDEFINED;2533description.final_layout = RDD::TEXTURE_LAYOUT_UNDEFINED;2534}2535}25362537attachment_last_pass[i] = -1;2538attachment_remap.push_back(attachments.size());2539attachments.push_back(description);2540}25412542LocalVector<RDD::Subpass> subpasses;2543subpasses.resize(p_passes.size());2544LocalVector<RDD::SubpassDependency> subpass_dependencies;25452546for (int i = 0; i < p_passes.size(); i++) {2547const FramebufferPass *pass = &p_passes[i];2548RDD::Subpass &subpass = subpasses[i];25492550TextureSamples texture_samples = TEXTURE_SAMPLES_1;2551bool is_multisample_first = true;25522553for (int j = 0; j < pass->color_attachments.size(); j++) {2554int32_t attachment = pass->color_attachments[j];2555RDD::AttachmentReference reference;2556if (attachment == ATTACHMENT_UNUSED) {2557reference.attachment = RDD::AttachmentReference::UNUSED;2558reference.layout = RDD::TEXTURE_LAYOUT_UNDEFINED;2559} else {2560ERR_FAIL_INDEX_V_MSG(attachment, p_attachments.size(), RDD::RenderPassID(), "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), color attachment (" + itos(j) + ").");2561ERR_FAIL_COND_V_MSG(!(p_attachments[attachment].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT), RDD::RenderPassID(), "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), it's marked as depth, but it's not usable as color attachment.");2562ERR_FAIL_COND_V_MSG(attachment_last_pass[attachment] == i, RDD::RenderPassID(), "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), it already was used for something else before in this pass.");25632564if (is_multisample_first) {2565texture_samples = p_attachments[attachment].samples;2566is_multisample_first = false;2567} else {2568ERR_FAIL_COND_V_MSG(texture_samples != p_attachments[attachment].samples, RDD::RenderPassID(), "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), if an attachment is marked as multisample, all of them should be multisample and use the same number of samples.");2569}2570reference.attachment = attachment_remap[attachment];2571reference.layout = RDD::TEXTURE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;2572attachment_last_pass[attachment] = i;2573}2574reference.aspect = RDD::TEXTURE_ASPECT_COLOR_BIT;2575subpass.color_references.push_back(reference);2576}25772578for (int j = 0; j < pass->input_attachments.size(); j++) {2579int32_t attachment = pass->input_attachments[j];2580RDD::AttachmentReference reference;2581if (attachment == ATTACHMENT_UNUSED) {2582reference.attachment = RDD::AttachmentReference::UNUSED;2583reference.layout = RDD::TEXTURE_LAYOUT_UNDEFINED;2584} else {2585ERR_FAIL_INDEX_V_MSG(attachment, p_attachments.size(), RDD::RenderPassID(), "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), input attachment (" + itos(j) + ").");2586ERR_FAIL_COND_V_MSG(!(p_attachments[attachment].usage_flags & TEXTURE_USAGE_INPUT_ATTACHMENT_BIT), RDD::RenderPassID(), "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), it isn't marked as an input texture.");2587ERR_FAIL_COND_V_MSG(attachment_last_pass[attachment] == i, RDD::RenderPassID(), "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), it already was used for something else before in this pass.");2588reference.attachment = attachment_remap[attachment];2589reference.layout = RDD::TEXTURE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;2590attachment_last_pass[attachment] = i;2591}2592reference.aspect = RDD::TEXTURE_ASPECT_COLOR_BIT;2593subpass.input_references.push_back(reference);2594}25952596if (pass->resolve_attachments.size() > 0) {2597ERR_FAIL_COND_V_MSG(pass->resolve_attachments.size() != pass->color_attachments.size(), RDD::RenderPassID(), "The amount of resolve attachments (" + itos(pass->resolve_attachments.size()) + ") must match the number of color attachments (" + itos(pass->color_attachments.size()) + ").");2598ERR_FAIL_COND_V_MSG(texture_samples == TEXTURE_SAMPLES_1, RDD::RenderPassID(), "Resolve attachments specified, but color attachments are not multisample.");2599}2600for (int j = 0; j < pass->resolve_attachments.size(); j++) {2601int32_t attachment = pass->resolve_attachments[j];2602attachments[attachment].load_op = RDD::ATTACHMENT_LOAD_OP_DONT_CARE;26032604RDD::AttachmentReference reference;2605if (attachment == ATTACHMENT_UNUSED) {2606reference.attachment = RDD::AttachmentReference::UNUSED;2607reference.layout = RDD::TEXTURE_LAYOUT_UNDEFINED;2608} else {2609ERR_FAIL_INDEX_V_MSG(attachment, p_attachments.size(), RDD::RenderPassID(), "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), resolve attachment (" + itos(j) + ").");2610ERR_FAIL_COND_V_MSG(pass->color_attachments[j] == ATTACHMENT_UNUSED, RDD::RenderPassID(), "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), resolve attachment (" + itos(j) + "), the respective color attachment is marked as unused.");2611ERR_FAIL_COND_V_MSG(!(p_attachments[attachment].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT), RDD::RenderPassID(), "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), resolve attachment, it isn't marked as a color texture.");2612ERR_FAIL_COND_V_MSG(attachment_last_pass[attachment] == i, RDD::RenderPassID(), "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), it already was used for something else before in this pass.");2613bool multisample = p_attachments[attachment].samples > TEXTURE_SAMPLES_1;2614ERR_FAIL_COND_V_MSG(multisample, RDD::RenderPassID(), "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), resolve attachments can't be multisample.");2615reference.attachment = attachment_remap[attachment];2616reference.layout = RDD::TEXTURE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; // RDD::TEXTURE_LAYOUT_SHADER_READ_ONLY_OPTIMAL2617attachment_last_pass[attachment] = i;2618}2619reference.aspect = RDD::TEXTURE_ASPECT_COLOR_BIT;2620subpass.resolve_references.push_back(reference);2621}26222623if (pass->depth_attachment != ATTACHMENT_UNUSED) {2624int32_t attachment = pass->depth_attachment;2625ERR_FAIL_INDEX_V_MSG(attachment, p_attachments.size(), RDD::RenderPassID(), "Invalid framebuffer depth format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), depth attachment.");2626ERR_FAIL_COND_V_MSG(!(p_attachments[attachment].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT), RDD::RenderPassID(), "Invalid framebuffer depth format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), it's marked as depth, but it's not a depth attachment.");2627ERR_FAIL_COND_V_MSG(attachment_last_pass[attachment] == i, RDD::RenderPassID(), "Invalid framebuffer depth format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), it already was used for something else before in this pass.");2628subpass.depth_stencil_reference.attachment = attachment_remap[attachment];2629subpass.depth_stencil_reference.layout = RDD::TEXTURE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;2630attachment_last_pass[attachment] = i;26312632if (is_multisample_first) {2633texture_samples = p_attachments[attachment].samples;2634is_multisample_first = false;2635} else {2636ERR_FAIL_COND_V_MSG(texture_samples != p_attachments[attachment].samples, RDD::RenderPassID(), "Invalid framebuffer depth format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), if an attachment is marked as multisample, all of them should be multisample and use the same number of samples including the depth.");2637}26382639} else {2640subpass.depth_stencil_reference.attachment = RDD::AttachmentReference::UNUSED;2641subpass.depth_stencil_reference.layout = RDD::TEXTURE_LAYOUT_UNDEFINED;2642}26432644if (p_vrs_method == VRS_METHOD_FRAGMENT_SHADING_RATE && p_vrs_attachment >= 0) {2645int32_t attachment = p_vrs_attachment;2646ERR_FAIL_INDEX_V_MSG(attachment, p_attachments.size(), RDD::RenderPassID(), "Invalid framebuffer VRS format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), VRS attachment.");2647ERR_FAIL_COND_V_MSG(!(p_attachments[attachment].usage_flags & TEXTURE_USAGE_VRS_ATTACHMENT_BIT), RDD::RenderPassID(), "Invalid framebuffer VRS format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), it's marked as VRS, but it's not a VRS attachment.");2648ERR_FAIL_COND_V_MSG(attachment_last_pass[attachment] == i, RDD::RenderPassID(), "Invalid framebuffer VRS attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), it already was used for something else before in this pass.");26492650subpass.fragment_shading_rate_reference.attachment = attachment_remap[attachment];2651subpass.fragment_shading_rate_reference.layout = RDD::TEXTURE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL;2652subpass.fragment_shading_rate_texel_size = p_vrs_texel_size;26532654attachment_last_pass[attachment] = i;2655}26562657for (int j = 0; j < pass->preserve_attachments.size(); j++) {2658int32_t attachment = pass->preserve_attachments[j];26592660ERR_FAIL_COND_V_MSG(attachment == ATTACHMENT_UNUSED, RDD::RenderPassID(), "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), preserve attachment (" + itos(j) + "). Preserve attachments can't be unused.");26612662ERR_FAIL_INDEX_V_MSG(attachment, p_attachments.size(), RDD::RenderPassID(), "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), preserve attachment (" + itos(j) + ").");26632664if (attachment_last_pass[attachment] != i) {2665// Preserve can still be used to keep depth or color from being discarded after use.2666attachment_last_pass[attachment] = i;2667subpasses[i].preserve_attachments.push_back(attachment);2668}2669}26702671if (r_samples) {2672r_samples->push_back(texture_samples);2673}26742675if (i > 0) {2676RDD::SubpassDependency dependency;2677dependency.src_subpass = i - 1;2678dependency.dst_subpass = i;2679dependency.src_stages = (RDD::PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | RDD::PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | RDD::PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT);2680dependency.dst_stages = (RDD::PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | RDD::PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | RDD::PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT | RDD::PIPELINE_STAGE_FRAGMENT_SHADER_BIT);2681dependency.src_access = (RDD::BARRIER_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | RDD::BARRIER_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT);2682dependency.dst_access = (RDD::BARRIER_ACCESS_COLOR_ATTACHMENT_READ_BIT | RDD::BARRIER_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | RDD::BARRIER_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | RDD::BARRIER_ACCESS_INPUT_ATTACHMENT_READ_BIT);2683subpass_dependencies.push_back(dependency);2684}2685}26862687RDD::AttachmentReference fragment_density_map_attachment_reference;2688if (p_vrs_method == VRS_METHOD_FRAGMENT_DENSITY_MAP && p_vrs_attachment >= 0) {2689fragment_density_map_attachment_reference.attachment = p_vrs_attachment;2690fragment_density_map_attachment_reference.layout = RDD::TEXTURE_LAYOUT_FRAGMENT_DENSITY_MAP_ATTACHMENT_OPTIMAL;2691}26922693RDD::RenderPassID render_pass = p_driver->render_pass_create(attachments, subpasses, subpass_dependencies, p_view_count, fragment_density_map_attachment_reference);2694ERR_FAIL_COND_V(!render_pass, RDD::RenderPassID());26952696return render_pass;2697}26982699RDD::RenderPassID RenderingDevice::_render_pass_create_from_graph(RenderingDeviceDriver *p_driver, VectorView<RDD::AttachmentLoadOp> p_load_ops, VectorView<RDD::AttachmentStoreOp> p_store_ops, void *p_user_data) {2700DEV_ASSERT(p_driver != nullptr);2701DEV_ASSERT(p_user_data != nullptr);27022703// The graph delegates the creation of the render pass to the user according to the load and store ops that were determined as necessary after2704// resolving the dependencies between commands. This function creates a render pass for the framebuffer accordingly.2705Framebuffer *framebuffer = (Framebuffer *)(p_user_data);2706const FramebufferFormatKey &key = framebuffer->rendering_device->framebuffer_formats[framebuffer->format_id].E->key();2707return _render_pass_create(p_driver, key.attachments, key.passes, p_load_ops, p_store_ops, framebuffer->view_count, key.vrs_method, key.vrs_attachment, key.vrs_texel_size);2708}27092710RDG::ResourceUsage RenderingDevice::_vrs_usage_from_method(VRSMethod p_method) {2711switch (p_method) {2712case VRS_METHOD_FRAGMENT_SHADING_RATE:2713return RDG::RESOURCE_USAGE_ATTACHMENT_FRAGMENT_SHADING_RATE_READ;2714case VRS_METHOD_FRAGMENT_DENSITY_MAP:2715return RDG::RESOURCE_USAGE_ATTACHMENT_FRAGMENT_DENSITY_MAP_READ;2716default:2717return RDG::RESOURCE_USAGE_NONE;2718}2719}27202721RDD::PipelineStageBits RenderingDevice::_vrs_stages_from_method(VRSMethod p_method) {2722switch (p_method) {2723case VRS_METHOD_FRAGMENT_SHADING_RATE:2724return RDD::PIPELINE_STAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT;2725case VRS_METHOD_FRAGMENT_DENSITY_MAP:2726return RDD::PIPELINE_STAGE_FRAGMENT_DENSITY_PROCESS_BIT;2727default:2728return RDD::PipelineStageBits(0);2729}2730}27312732RDD::TextureLayout RenderingDevice::_vrs_layout_from_method(VRSMethod p_method) {2733switch (p_method) {2734case VRS_METHOD_FRAGMENT_SHADING_RATE:2735return RDD::TEXTURE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL;2736case VRS_METHOD_FRAGMENT_DENSITY_MAP:2737return RDD::TEXTURE_LAYOUT_FRAGMENT_DENSITY_MAP_ATTACHMENT_OPTIMAL;2738default:2739return RDD::TEXTURE_LAYOUT_UNDEFINED;2740}2741}27422743void RenderingDevice::_vrs_detect_method() {2744const RDD::FragmentShadingRateCapabilities &fsr_capabilities = driver->get_fragment_shading_rate_capabilities();2745const RDD::FragmentDensityMapCapabilities &fdm_capabilities = driver->get_fragment_density_map_capabilities();2746if (fsr_capabilities.attachment_supported) {2747vrs_method = VRS_METHOD_FRAGMENT_SHADING_RATE;2748} else if (fdm_capabilities.attachment_supported) {2749vrs_method = VRS_METHOD_FRAGMENT_DENSITY_MAP;2750}27512752switch (vrs_method) {2753case VRS_METHOD_FRAGMENT_SHADING_RATE:2754vrs_format = DATA_FORMAT_R8_UINT;2755vrs_texel_size = Vector2i(16, 16).clamp(fsr_capabilities.min_texel_size, fsr_capabilities.max_texel_size);2756break;2757case VRS_METHOD_FRAGMENT_DENSITY_MAP:2758vrs_format = DATA_FORMAT_R8G8_UNORM;2759vrs_texel_size = Vector2i(32, 32).clamp(fdm_capabilities.min_texel_size, fdm_capabilities.max_texel_size);2760break;2761default:2762break;2763}2764}27652766RD::VRSMethod RenderingDevice::vrs_get_method() const {2767return vrs_method;2768}27692770RD::DataFormat RenderingDevice::vrs_get_format() const {2771return vrs_format;2772}27732774Size2i RenderingDevice::vrs_get_texel_size() const {2775return vrs_texel_size;2776}27772778RenderingDevice::FramebufferFormatID RenderingDevice::framebuffer_format_create(const Vector<AttachmentFormat> &p_format, uint32_t p_view_count, int32_t p_fragment_density_map_attachment) {2779FramebufferPass pass;2780for (int i = 0; i < p_format.size(); i++) {2781if (p_format[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {2782pass.depth_attachment = i;2783} else {2784pass.color_attachments.push_back(i);2785}2786}27872788Vector<FramebufferPass> passes;2789passes.push_back(pass);2790return framebuffer_format_create_multipass(p_format, passes, p_view_count, p_fragment_density_map_attachment);2791}27922793RenderingDevice::FramebufferFormatID RenderingDevice::framebuffer_format_create_multipass(const Vector<AttachmentFormat> &p_attachments, const Vector<FramebufferPass> &p_passes, uint32_t p_view_count, int32_t p_vrs_attachment) {2794_THREAD_SAFE_METHOD_27952796FramebufferFormatKey key;2797key.attachments = p_attachments;2798key.passes = p_passes;2799key.view_count = p_view_count;2800key.vrs_method = vrs_method;2801key.vrs_attachment = p_vrs_attachment;2802key.vrs_texel_size = vrs_texel_size;28032804const RBMap<FramebufferFormatKey, FramebufferFormatID>::Element *E = framebuffer_format_cache.find(key);2805if (E) {2806// Exists, return.2807return E->get();2808}28092810Vector<TextureSamples> samples;2811LocalVector<RDD::AttachmentLoadOp> load_ops;2812LocalVector<RDD::AttachmentStoreOp> store_ops;2813for (int64_t i = 0; i < p_attachments.size(); i++) {2814load_ops.push_back(RDD::ATTACHMENT_LOAD_OP_CLEAR);2815store_ops.push_back(RDD::ATTACHMENT_STORE_OP_STORE);2816}28172818RDD::RenderPassID render_pass = _render_pass_create(driver, p_attachments, p_passes, load_ops, store_ops, p_view_count, vrs_method, p_vrs_attachment, vrs_texel_size, &samples); // Actions don't matter for this use case.2819if (!render_pass) { // Was likely invalid.2820return INVALID_ID;2821}28222823FramebufferFormatID id = FramebufferFormatID(framebuffer_format_cache.size()) | (FramebufferFormatID(ID_TYPE_FRAMEBUFFER_FORMAT) << FramebufferFormatID(ID_BASE_SHIFT));2824E = framebuffer_format_cache.insert(key, id);28252826FramebufferFormat fb_format;2827fb_format.E = E;2828fb_format.render_pass = render_pass;2829fb_format.pass_samples = samples;2830fb_format.view_count = p_view_count;2831framebuffer_formats[id] = fb_format;28322833#if PRINT_FRAMEBUFFER_FORMAT2834print_line("FRAMEBUFFER FORMAT:", id, "ATTACHMENTS:", p_attachments.size(), "PASSES:", p_passes.size());2835for (RD::AttachmentFormat attachment : p_attachments) {2836print_line("FORMAT:", attachment.format, "SAMPLES:", attachment.samples, "USAGE FLAGS:", attachment.usage_flags);2837}2838#endif28392840return id;2841}28422843RenderingDevice::FramebufferFormatID RenderingDevice::framebuffer_format_create_empty(TextureSamples p_samples) {2844_THREAD_SAFE_METHOD_28452846FramebufferFormatKey key;2847key.passes.push_back(FramebufferPass());28482849const RBMap<FramebufferFormatKey, FramebufferFormatID>::Element *E = framebuffer_format_cache.find(key);2850if (E) {2851// Exists, return.2852return E->get();2853}28542855LocalVector<RDD::Subpass> subpass;2856subpass.resize(1);28572858RDD::RenderPassID render_pass = driver->render_pass_create({}, subpass, {}, 1, RDD::AttachmentReference());2859ERR_FAIL_COND_V(!render_pass, FramebufferFormatID());28602861FramebufferFormatID id = FramebufferFormatID(framebuffer_format_cache.size()) | (FramebufferFormatID(ID_TYPE_FRAMEBUFFER_FORMAT) << FramebufferFormatID(ID_BASE_SHIFT));28622863E = framebuffer_format_cache.insert(key, id);28642865FramebufferFormat fb_format;2866fb_format.E = E;2867fb_format.render_pass = render_pass;2868fb_format.pass_samples.push_back(p_samples);2869framebuffer_formats[id] = fb_format;28702871#if PRINT_FRAMEBUFFER_FORMAT2872print_line("FRAMEBUFFER FORMAT:", id, "ATTACHMENTS: EMPTY");2873#endif28742875return id;2876}28772878RenderingDevice::TextureSamples RenderingDevice::framebuffer_format_get_texture_samples(FramebufferFormatID p_format, uint32_t p_pass) {2879_THREAD_SAFE_METHOD_28802881HashMap<FramebufferFormatID, FramebufferFormat>::Iterator E = framebuffer_formats.find(p_format);2882ERR_FAIL_COND_V(!E, TEXTURE_SAMPLES_1);2883ERR_FAIL_COND_V(p_pass >= uint32_t(E->value.pass_samples.size()), TEXTURE_SAMPLES_1);28842885return E->value.pass_samples[p_pass];2886}28872888RID RenderingDevice::framebuffer_create_empty(const Size2i &p_size, TextureSamples p_samples, FramebufferFormatID p_format_check) {2889_THREAD_SAFE_METHOD_28902891Framebuffer framebuffer;2892framebuffer.rendering_device = this;2893framebuffer.format_id = framebuffer_format_create_empty(p_samples);2894ERR_FAIL_COND_V(p_format_check != INVALID_FORMAT_ID && framebuffer.format_id != p_format_check, RID());2895framebuffer.size = p_size;2896framebuffer.view_count = 1;28972898RDG::FramebufferCache *framebuffer_cache = RDG::framebuffer_cache_create();2899framebuffer_cache->width = p_size.width;2900framebuffer_cache->height = p_size.height;2901framebuffer.framebuffer_cache = framebuffer_cache;29022903RID id = framebuffer_owner.make_rid(framebuffer);2904#ifdef DEV_ENABLED2905set_resource_name(id, "RID:" + itos(id.get_id()));2906#endif29072908framebuffer_cache->render_pass_creation_user_data = framebuffer_owner.get_or_null(id);29092910return id;2911}29122913RID RenderingDevice::framebuffer_create(const Vector<RID> &p_texture_attachments, FramebufferFormatID p_format_check, uint32_t p_view_count) {2914_THREAD_SAFE_METHOD_29152916FramebufferPass pass;29172918for (int i = 0; i < p_texture_attachments.size(); i++) {2919Texture *texture = texture_owner.get_or_null(p_texture_attachments[i]);29202921ERR_FAIL_COND_V_MSG(texture && texture->layers != p_view_count, RID(), "Layers of our texture doesn't match view count for this framebuffer");29222923if (texture != nullptr) {2924_check_transfer_worker_texture(texture);2925}29262927if (texture && texture->usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {2928pass.depth_attachment = i;2929} else if (texture && texture->usage_flags & TEXTURE_USAGE_VRS_ATTACHMENT_BIT) {2930// Prevent the VRS attachment from being added to the color_attachments.2931} else {2932if (texture && texture->is_resolve_buffer) {2933pass.resolve_attachments.push_back(i);2934} else {2935pass.color_attachments.push_back(texture ? i : ATTACHMENT_UNUSED);2936}2937}2938}29392940Vector<FramebufferPass> passes;2941passes.push_back(pass);29422943return framebuffer_create_multipass(p_texture_attachments, passes, p_format_check, p_view_count);2944}29452946RID RenderingDevice::framebuffer_create_multipass(const Vector<RID> &p_texture_attachments, const Vector<FramebufferPass> &p_passes, FramebufferFormatID p_format_check, uint32_t p_view_count) {2947_THREAD_SAFE_METHOD_29482949Vector<AttachmentFormat> attachments;2950LocalVector<RDD::TextureID> textures;2951LocalVector<RDG::ResourceTracker *> trackers;2952int32_t vrs_attachment = -1;2953attachments.resize(p_texture_attachments.size());2954Size2i size;2955bool size_set = false;2956for (int i = 0; i < p_texture_attachments.size(); i++) {2957AttachmentFormat af;2958Texture *texture = texture_owner.get_or_null(p_texture_attachments[i]);2959if (!texture) {2960af.usage_flags = AttachmentFormat::UNUSED_ATTACHMENT;2961trackers.push_back(nullptr);2962} else {2963ERR_FAIL_COND_V_MSG(texture->layers != p_view_count, RID(), "Layers of our texture doesn't match view count for this framebuffer");29642965_check_transfer_worker_texture(texture);29662967if (i != 0 && texture->usage_flags & TEXTURE_USAGE_VRS_ATTACHMENT_BIT) {2968// Detect if the texture is the fragment density map and it's not the first attachment.2969vrs_attachment = i;2970}29712972if (!size_set) {2973size.width = texture->width;2974size.height = texture->height;2975size_set = true;2976} else if (texture->usage_flags & TEXTURE_USAGE_VRS_ATTACHMENT_BIT) {2977// If this is not the first attachment we assume this is used as the VRS attachment.2978// In this case this texture will be 1/16th the size of the color attachment.2979// So we skip the size check.2980} else {2981ERR_FAIL_COND_V_MSG((uint32_t)size.width != texture->width || (uint32_t)size.height != texture->height, RID(),2982"All textures in a framebuffer should be the same size.");2983}29842985af.format = texture->format;2986af.samples = texture->samples;2987af.usage_flags = texture->usage_flags;29882989_texture_make_mutable(texture, p_texture_attachments[i]);29902991textures.push_back(texture->driver_id);2992trackers.push_back(texture->draw_tracker);2993}2994attachments.write[i] = af;2995}29962997ERR_FAIL_COND_V_MSG(!size_set, RID(), "All attachments unused.");29982999FramebufferFormatID format_id = framebuffer_format_create_multipass(attachments, p_passes, p_view_count, vrs_attachment);3000if (format_id == INVALID_ID) {3001return RID();3002}30033004ERR_FAIL_COND_V_MSG(p_format_check != INVALID_ID && format_id != p_format_check, RID(),3005"The format used to check this framebuffer differs from the intended framebuffer format.");30063007Framebuffer framebuffer;3008framebuffer.rendering_device = this;3009framebuffer.format_id = format_id;3010framebuffer.texture_ids = p_texture_attachments;3011framebuffer.size = size;3012framebuffer.view_count = p_view_count;30133014RDG::FramebufferCache *framebuffer_cache = RDG::framebuffer_cache_create();3015framebuffer_cache->width = size.width;3016framebuffer_cache->height = size.height;3017framebuffer_cache->textures = textures;3018framebuffer_cache->trackers = trackers;3019framebuffer.framebuffer_cache = framebuffer_cache;30203021RID id = framebuffer_owner.make_rid(framebuffer);3022#ifdef DEV_ENABLED3023set_resource_name(id, "RID:" + itos(id.get_id()));3024#endif30253026for (int i = 0; i < p_texture_attachments.size(); i++) {3027if (p_texture_attachments[i].is_valid()) {3028_add_dependency(id, p_texture_attachments[i]);3029}3030}30313032framebuffer_cache->render_pass_creation_user_data = framebuffer_owner.get_or_null(id);30333034return id;3035}30363037RenderingDevice::FramebufferFormatID RenderingDevice::framebuffer_get_format(RID p_framebuffer) {3038_THREAD_SAFE_METHOD_30393040Framebuffer *framebuffer = framebuffer_owner.get_or_null(p_framebuffer);3041ERR_FAIL_NULL_V(framebuffer, INVALID_ID);30423043return framebuffer->format_id;3044}30453046Size2 RenderingDevice::framebuffer_get_size(RID p_framebuffer) {3047_THREAD_SAFE_METHOD_30483049Framebuffer *framebuffer = framebuffer_owner.get_or_null(p_framebuffer);3050ERR_FAIL_NULL_V(framebuffer, Size2(0, 0));30513052return framebuffer->size;3053}30543055bool RenderingDevice::framebuffer_is_valid(RID p_framebuffer) const {3056_THREAD_SAFE_METHOD_30573058return framebuffer_owner.owns(p_framebuffer);3059}30603061void RenderingDevice::framebuffer_set_invalidation_callback(RID p_framebuffer, InvalidationCallback p_callback, void *p_userdata) {3062_THREAD_SAFE_METHOD_30633064Framebuffer *framebuffer = framebuffer_owner.get_or_null(p_framebuffer);3065ERR_FAIL_NULL(framebuffer);30663067framebuffer->invalidated_callback = p_callback;3068framebuffer->invalidated_callback_userdata = p_userdata;3069}30703071/*****************/3072/**** SAMPLER ****/3073/*****************/30743075RID RenderingDevice::sampler_create(const SamplerState &p_state) {3076_THREAD_SAFE_METHOD_30773078ERR_FAIL_INDEX_V(p_state.repeat_u, SAMPLER_REPEAT_MODE_MAX, RID());3079ERR_FAIL_INDEX_V(p_state.repeat_v, SAMPLER_REPEAT_MODE_MAX, RID());3080ERR_FAIL_INDEX_V(p_state.repeat_w, SAMPLER_REPEAT_MODE_MAX, RID());3081ERR_FAIL_INDEX_V(p_state.compare_op, COMPARE_OP_MAX, RID());3082ERR_FAIL_INDEX_V(p_state.border_color, SAMPLER_BORDER_COLOR_MAX, RID());30833084RDD::SamplerID sampler = driver->sampler_create(p_state);3085ERR_FAIL_COND_V(!sampler, RID());30863087RID id = sampler_owner.make_rid(sampler);3088#ifdef DEV_ENABLED3089set_resource_name(id, "RID:" + itos(id.get_id()));3090#endif3091return id;3092}30933094bool RenderingDevice::sampler_is_format_supported_for_filter(DataFormat p_format, SamplerFilter p_sampler_filter) const {3095_THREAD_SAFE_METHOD_30963097ERR_FAIL_INDEX_V(p_format, DATA_FORMAT_MAX, false);30983099return driver->sampler_is_format_supported_for_filter(p_format, p_sampler_filter);3100}31013102/***********************/3103/**** VERTEX BUFFER ****/3104/***********************/31053106RID RenderingDevice::vertex_buffer_create(uint32_t p_size_bytes, Span<uint8_t> p_data, BitField<BufferCreationBits> p_creation_bits) {3107ERR_FAIL_COND_V(p_data.size() && (uint32_t)p_data.size() != p_size_bytes, RID());31083109Buffer buffer;3110buffer.size = p_size_bytes;3111buffer.usage = RDD::BUFFER_USAGE_TRANSFER_FROM_BIT | RDD::BUFFER_USAGE_TRANSFER_TO_BIT | RDD::BUFFER_USAGE_VERTEX_BIT;3112if (p_creation_bits.has_flag(BUFFER_CREATION_AS_STORAGE_BIT)) {3113buffer.usage.set_flag(RDD::BUFFER_USAGE_STORAGE_BIT);3114}3115if (p_creation_bits.has_flag(BUFFER_CREATION_DEVICE_ADDRESS_BIT)) {3116buffer.usage.set_flag(RDD::BUFFER_USAGE_DEVICE_ADDRESS_BIT);3117}3118buffer.driver_id = driver->buffer_create(buffer.size, buffer.usage, RDD::MEMORY_ALLOCATION_TYPE_GPU);3119ERR_FAIL_COND_V(!buffer.driver_id, RID());31203121// Vertex buffers are assumed to be immutable unless they don't have initial data or they've been marked for storage explicitly.3122if (p_data.is_empty() || p_creation_bits.has_flag(BUFFER_CREATION_AS_STORAGE_BIT)) {3123buffer.draw_tracker = RDG::resource_tracker_create();3124buffer.draw_tracker->buffer_driver_id = buffer.driver_id;3125}31263127if (p_data.size()) {3128_buffer_initialize(&buffer, p_data);3129}31303131_THREAD_SAFE_LOCK_3132buffer_memory += buffer.size;3133_THREAD_SAFE_UNLOCK_31343135RID id = vertex_buffer_owner.make_rid(buffer);3136#ifdef DEV_ENABLED3137set_resource_name(id, "RID:" + itos(id.get_id()));3138#endif3139return id;3140}31413142// 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.3143RenderingDevice::VertexFormatID RenderingDevice::vertex_format_create(const Vector<VertexAttribute> &p_vertex_descriptions) {3144_THREAD_SAFE_METHOD_31453146VertexDescriptionKey key;3147key.vertex_formats = p_vertex_descriptions;31483149VertexFormatID *idptr = vertex_format_cache.getptr(key);3150if (idptr) {3151return *idptr;3152}31533154HashSet<int> used_locations;3155for (int i = 0; i < p_vertex_descriptions.size(); i++) {3156ERR_CONTINUE(p_vertex_descriptions[i].format >= DATA_FORMAT_MAX);3157ERR_FAIL_COND_V(used_locations.has(p_vertex_descriptions[i].location), INVALID_ID);31583159ERR_FAIL_COND_V_MSG(get_format_vertex_size(p_vertex_descriptions[i].format) == 0, INVALID_ID,3160"Data format for attachment (" + itos(i) + "), '" + FORMAT_NAMES[p_vertex_descriptions[i].format] + "', is not valid for a vertex array.");31613162used_locations.insert(p_vertex_descriptions[i].location);3163}31643165RDD::VertexFormatID driver_id = driver->vertex_format_create(p_vertex_descriptions);3166ERR_FAIL_COND_V(!driver_id, 0);31673168VertexFormatID id = (vertex_format_cache.size() | ((int64_t)ID_TYPE_VERTEX_FORMAT << ID_BASE_SHIFT));3169vertex_format_cache[key] = id;3170vertex_formats[id].vertex_formats = p_vertex_descriptions;3171vertex_formats[id].driver_id = driver_id;3172return id;3173}31743175RID RenderingDevice::vertex_array_create(uint32_t p_vertex_count, VertexFormatID p_vertex_format, const Vector<RID> &p_src_buffers, const Vector<uint64_t> &p_offsets) {3176_THREAD_SAFE_METHOD_31773178ERR_FAIL_COND_V(!vertex_formats.has(p_vertex_format), RID());3179const VertexDescriptionCache &vd = vertex_formats[p_vertex_format];31803181ERR_FAIL_COND_V(vd.vertex_formats.size() != p_src_buffers.size(), RID());31823183for (int i = 0; i < p_src_buffers.size(); i++) {3184ERR_FAIL_COND_V(!vertex_buffer_owner.owns(p_src_buffers[i]), RID());3185}31863187VertexArray vertex_array;31883189if (p_offsets.is_empty()) {3190vertex_array.offsets.resize_initialized(p_src_buffers.size());3191} else {3192ERR_FAIL_COND_V(p_offsets.size() != p_src_buffers.size(), RID());3193vertex_array.offsets = p_offsets;3194}31953196vertex_array.vertex_count = p_vertex_count;3197vertex_array.description = p_vertex_format;3198vertex_array.max_instances_allowed = 0xFFFFFFFF; // By default as many as you want.3199for (int i = 0; i < p_src_buffers.size(); i++) {3200Buffer *buffer = vertex_buffer_owner.get_or_null(p_src_buffers[i]);32013202// Validate with buffer.3203{3204const VertexAttribute &atf = vd.vertex_formats[i];32053206uint32_t element_size = get_format_vertex_size(atf.format);3207ERR_FAIL_COND_V(element_size == 0, RID()); // Should never happens since this was prevalidated.32083209if (atf.frequency == VERTEX_FREQUENCY_VERTEX) {3210// Validate size for regular drawing.3211uint64_t total_size = uint64_t(atf.stride) * (p_vertex_count - 1) + atf.offset + element_size;3212ERR_FAIL_COND_V_MSG(total_size > buffer->size, RID(),3213"Attachment (" + itos(i) + ") will read past the end of the buffer.");32143215} else {3216// Validate size for instances drawing.3217uint64_t available = buffer->size - atf.offset;3218ERR_FAIL_COND_V_MSG(available < element_size, RID(),3219"Attachment (" + itos(i) + ") uses instancing, but it's just too small.");32203221uint32_t instances_allowed = available / atf.stride;3222vertex_array.max_instances_allowed = MIN(instances_allowed, vertex_array.max_instances_allowed);3223}3224}32253226vertex_array.buffers.push_back(buffer->driver_id);32273228if (buffer->draw_tracker != nullptr) {3229vertex_array.draw_trackers.push_back(buffer->draw_tracker);3230} else {3231vertex_array.untracked_buffers.insert(p_src_buffers[i]);3232}32333234if (buffer->transfer_worker_index >= 0) {3235vertex_array.transfer_worker_indices.push_back(buffer->transfer_worker_index);3236vertex_array.transfer_worker_operations.push_back(buffer->transfer_worker_operation);3237}3238}32393240RID id = vertex_array_owner.make_rid(vertex_array);3241for (int i = 0; i < p_src_buffers.size(); i++) {3242_add_dependency(id, p_src_buffers[i]);3243}32443245return id;3246}32473248RID RenderingDevice::index_buffer_create(uint32_t p_index_count, IndexBufferFormat p_format, Span<uint8_t> p_data, bool p_use_restart_indices, BitField<BufferCreationBits> p_creation_bits) {3249ERR_FAIL_COND_V(p_index_count == 0, RID());32503251IndexBuffer index_buffer;3252index_buffer.format = p_format;3253index_buffer.supports_restart_indices = p_use_restart_indices;3254index_buffer.index_count = p_index_count;3255uint32_t size_bytes = p_index_count * ((p_format == INDEX_BUFFER_FORMAT_UINT16) ? 2 : 4);3256#ifdef DEBUG_ENABLED3257if (p_data.size()) {3258index_buffer.max_index = 0;3259ERR_FAIL_COND_V_MSG((uint32_t)p_data.size() != size_bytes, RID(),3260"Default index buffer initializer array size (" + itos(p_data.size()) + ") does not match format required size (" + itos(size_bytes) + ").");3261const uint8_t *r = p_data.ptr();3262if (p_format == INDEX_BUFFER_FORMAT_UINT16) {3263const uint16_t *index16 = (const uint16_t *)r;3264for (uint32_t i = 0; i < p_index_count; i++) {3265if (p_use_restart_indices && index16[i] == 0xFFFF) {3266continue; // Restart index, ignore.3267}3268index_buffer.max_index = MAX(index16[i], index_buffer.max_index);3269}3270} else {3271const uint32_t *index32 = (const uint32_t *)r;3272for (uint32_t i = 0; i < p_index_count; i++) {3273if (p_use_restart_indices && index32[i] == 0xFFFFFFFF) {3274continue; // Restart index, ignore.3275}3276index_buffer.max_index = MAX(index32[i], index_buffer.max_index);3277}3278}3279} else {3280index_buffer.max_index = 0xFFFFFFFF;3281}3282#else3283index_buffer.max_index = 0xFFFFFFFF;3284#endif3285index_buffer.size = size_bytes;3286index_buffer.usage = (RDD::BUFFER_USAGE_TRANSFER_FROM_BIT | RDD::BUFFER_USAGE_TRANSFER_TO_BIT | RDD::BUFFER_USAGE_INDEX_BIT);3287if (p_creation_bits.has_flag(BUFFER_CREATION_DEVICE_ADDRESS_BIT)) {3288index_buffer.usage.set_flag(RDD::BUFFER_USAGE_DEVICE_ADDRESS_BIT);3289}3290index_buffer.driver_id = driver->buffer_create(index_buffer.size, index_buffer.usage, RDD::MEMORY_ALLOCATION_TYPE_GPU);3291ERR_FAIL_COND_V(!index_buffer.driver_id, RID());32923293// Index buffers are assumed to be immutable unless they don't have initial data.3294if (p_data.is_empty()) {3295index_buffer.draw_tracker = RDG::resource_tracker_create();3296index_buffer.draw_tracker->buffer_driver_id = index_buffer.driver_id;3297}32983299if (p_data.size()) {3300_buffer_initialize(&index_buffer, p_data);3301}33023303_THREAD_SAFE_LOCK_3304buffer_memory += index_buffer.size;3305_THREAD_SAFE_UNLOCK_33063307RID id = index_buffer_owner.make_rid(index_buffer);3308#ifdef DEV_ENABLED3309set_resource_name(id, "RID:" + itos(id.get_id()));3310#endif3311return id;3312}33133314RID RenderingDevice::index_array_create(RID p_index_buffer, uint32_t p_index_offset, uint32_t p_index_count) {3315_THREAD_SAFE_METHOD_33163317ERR_FAIL_COND_V(!index_buffer_owner.owns(p_index_buffer), RID());33183319IndexBuffer *index_buffer = index_buffer_owner.get_or_null(p_index_buffer);33203321ERR_FAIL_COND_V(p_index_count == 0, RID());3322ERR_FAIL_COND_V(p_index_offset + p_index_count > index_buffer->index_count, RID());33233324IndexArray index_array;3325index_array.max_index = index_buffer->max_index;3326index_array.driver_id = index_buffer->driver_id;3327index_array.draw_tracker = index_buffer->draw_tracker;3328index_array.offset = p_index_offset;3329index_array.indices = p_index_count;3330index_array.format = index_buffer->format;3331index_array.supports_restart_indices = index_buffer->supports_restart_indices;3332index_array.transfer_worker_index = index_buffer->transfer_worker_index;3333index_array.transfer_worker_operation = index_buffer->transfer_worker_operation;33343335RID id = index_array_owner.make_rid(index_array);3336_add_dependency(id, p_index_buffer);3337return id;3338}33393340/****************/3341/**** SHADER ****/3342/****************/33433344static const char *SHADER_UNIFORM_NAMES[RenderingDevice::UNIFORM_TYPE_MAX] = {3345"Sampler", "CombinedSampler", "Texture", "Image", "TextureBuffer", "SamplerTextureBuffer", "ImageBuffer", "UniformBuffer", "StorageBuffer", "InputAttachment"3346};33473348String RenderingDevice::_shader_uniform_debug(RID p_shader, int p_set) {3349String ret;3350const Shader *shader = shader_owner.get_or_null(p_shader);3351ERR_FAIL_NULL_V(shader, String());3352for (int i = 0; i < shader->uniform_sets.size(); i++) {3353if (p_set >= 0 && i != p_set) {3354continue;3355}3356for (int j = 0; j < shader->uniform_sets[i].size(); j++) {3357const ShaderUniform &ui = shader->uniform_sets[i][j];3358if (!ret.is_empty()) {3359ret += "\n";3360}3361ret += "Set: " + itos(i) + " Binding: " + itos(ui.binding) + " Type: " + SHADER_UNIFORM_NAMES[ui.type] + " Writable: " + (ui.writable ? "Y" : "N") + " Length: " + itos(ui.length);3362}3363}3364return ret;3365}33663367Vector<uint8_t> RenderingDevice::shader_compile_binary_from_spirv(const Vector<ShaderStageSPIRVData> &p_spirv, const String &p_shader_name) {3368ShaderReflection shader_refl;3369if (reflect_spirv(p_spirv, shader_refl) != OK) {3370return Vector<uint8_t>();3371}33723373const RenderingShaderContainerFormat &container_format = driver->get_shader_container_format();3374Ref<RenderingShaderContainer> shader_container = container_format.create_container();3375ERR_FAIL_COND_V(shader_container.is_null(), Vector<uint8_t>());33763377shader_container->set_from_shader_reflection(p_shader_name, shader_refl);33783379// Compile shader binary from SPIR-V.3380bool code_compiled = shader_container->set_code_from_spirv(p_spirv);3381ERR_FAIL_COND_V_MSG(!code_compiled, Vector<uint8_t>(), vformat("Failed to compile code to native for SPIR-V."));33823383return shader_container->to_bytes();3384}33853386RID RenderingDevice::shader_create_from_bytecode(const Vector<uint8_t> &p_shader_binary, RID p_placeholder) {3387// Immutable samplers :3388// Expanding api when creating shader to allow passing optionally a set of immutable samplers3389// keeping existing api but extending it by sending an empty set.3390Vector<PipelineImmutableSampler> immutable_samplers;3391return shader_create_from_bytecode_with_samplers(p_shader_binary, p_placeholder, immutable_samplers);3392}33933394RID RenderingDevice::shader_create_from_bytecode_with_samplers(const Vector<uint8_t> &p_shader_binary, RID p_placeholder, const Vector<PipelineImmutableSampler> &p_immutable_samplers) {3395_THREAD_SAFE_METHOD_33963397Ref<RenderingShaderContainer> shader_container = driver->get_shader_container_format().create_container();3398ERR_FAIL_COND_V(shader_container.is_null(), RID());33993400bool parsed_container = shader_container->from_bytes(p_shader_binary);3401ERR_FAIL_COND_V_MSG(!parsed_container, RID(), "Failed to parse shader container from binary.");34023403Vector<RDD::ImmutableSampler> driver_immutable_samplers;3404for (const PipelineImmutableSampler &source_sampler : p_immutable_samplers) {3405RDD::ImmutableSampler driver_sampler;3406driver_sampler.type = source_sampler.uniform_type;3407driver_sampler.binding = source_sampler.binding;34083409for (uint32_t j = 0; j < source_sampler.get_id_count(); j++) {3410RDD::SamplerID *sampler_driver_id = sampler_owner.get_or_null(source_sampler.get_id(j));3411driver_sampler.ids.push_back(*sampler_driver_id);3412}34133414driver_immutable_samplers.append(driver_sampler);3415}34163417RDD::ShaderID shader_id = driver->shader_create_from_container(shader_container, driver_immutable_samplers);3418ERR_FAIL_COND_V(!shader_id, RID());34193420// All good, let's create modules.34213422RID id;3423if (p_placeholder.is_null()) {3424id = shader_owner.make_rid();3425} else {3426id = p_placeholder;3427}34283429Shader *shader = shader_owner.get_or_null(id);3430ERR_FAIL_NULL_V(shader, RID());34313432*((ShaderReflection *)shader) = shader_container->get_shader_reflection();3433shader->name.clear();3434shader->name.append_utf8(shader_container->shader_name);3435shader->driver_id = shader_id;3436shader->layout_hash = driver->shader_get_layout_hash(shader_id);34373438for (int i = 0; i < shader->uniform_sets.size(); i++) {3439uint32_t format = 0; // No format, default.34403441if (shader->uniform_sets[i].size()) {3442// Sort and hash.34433444shader->uniform_sets.write[i].sort();34453446UniformSetFormat usformat;3447usformat.uniforms = shader->uniform_sets[i];3448RBMap<UniformSetFormat, uint32_t>::Element *E = uniform_set_format_cache.find(usformat);3449if (E) {3450format = E->get();3451} else {3452format = uniform_set_format_cache.size() + 1;3453uniform_set_format_cache.insert(usformat, format);3454}3455}34563457shader->set_formats.push_back(format);3458}34593460for (ShaderStage stage : shader->stages_vector) {3461switch (stage) {3462case SHADER_STAGE_VERTEX:3463shader->stage_bits.set_flag(RDD::PIPELINE_STAGE_VERTEX_SHADER_BIT);3464break;3465case SHADER_STAGE_FRAGMENT:3466shader->stage_bits.set_flag(RDD::PIPELINE_STAGE_FRAGMENT_SHADER_BIT);3467break;3468case SHADER_STAGE_TESSELATION_CONTROL:3469shader->stage_bits.set_flag(RDD::PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT);3470break;3471case SHADER_STAGE_TESSELATION_EVALUATION:3472shader->stage_bits.set_flag(RDD::PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT);3473break;3474case SHADER_STAGE_COMPUTE:3475shader->stage_bits.set_flag(RDD::PIPELINE_STAGE_COMPUTE_SHADER_BIT);3476break;3477default:3478DEV_ASSERT(false && "Unknown shader stage.");3479break;3480}3481}34823483#ifdef DEV_ENABLED3484set_resource_name(id, "RID:" + itos(id.get_id()));3485#endif3486return id;3487}34883489void RenderingDevice::shader_destroy_modules(RID p_shader) {3490Shader *shader = shader_owner.get_or_null(p_shader);3491ERR_FAIL_NULL(shader);3492driver->shader_destroy_modules(shader->driver_id);3493}34943495RID RenderingDevice::shader_create_placeholder() {3496_THREAD_SAFE_METHOD_34973498Shader shader;3499return shader_owner.make_rid(shader);3500}35013502uint64_t RenderingDevice::shader_get_vertex_input_attribute_mask(RID p_shader) {3503_THREAD_SAFE_METHOD_35043505const Shader *shader = shader_owner.get_or_null(p_shader);3506ERR_FAIL_NULL_V(shader, 0);3507return shader->vertex_input_mask;3508}35093510/******************/3511/**** UNIFORMS ****/3512/******************/35133514RID RenderingDevice::uniform_buffer_create(uint32_t p_size_bytes, Span<uint8_t> p_data, BitField<BufferCreationBits> p_creation_bits) {3515ERR_FAIL_COND_V(p_data.size() && (uint32_t)p_data.size() != p_size_bytes, RID());35163517Buffer buffer;3518buffer.size = p_size_bytes;3519buffer.usage = (RDD::BUFFER_USAGE_TRANSFER_TO_BIT | RDD::BUFFER_USAGE_UNIFORM_BIT);3520if (p_creation_bits.has_flag(BUFFER_CREATION_DEVICE_ADDRESS_BIT)) {3521buffer.usage.set_flag(RDD::BUFFER_USAGE_DEVICE_ADDRESS_BIT);3522}3523buffer.driver_id = driver->buffer_create(buffer.size, buffer.usage, RDD::MEMORY_ALLOCATION_TYPE_GPU);3524ERR_FAIL_COND_V(!buffer.driver_id, RID());35253526// Uniform buffers are assumed to be immutable unless they don't have initial data.3527if (p_data.is_empty()) {3528buffer.draw_tracker = RDG::resource_tracker_create();3529buffer.draw_tracker->buffer_driver_id = buffer.driver_id;3530}35313532if (p_data.size()) {3533_buffer_initialize(&buffer, p_data);3534}35353536_THREAD_SAFE_LOCK_3537buffer_memory += buffer.size;3538_THREAD_SAFE_UNLOCK_35393540RID id = uniform_buffer_owner.make_rid(buffer);3541#ifdef DEV_ENABLED3542set_resource_name(id, "RID:" + itos(id.get_id()));3543#endif3544return id;3545}35463547void RenderingDevice::_uniform_set_update_shared(UniformSet *p_uniform_set) {3548for (UniformSet::SharedTexture shared : p_uniform_set->shared_textures_to_update) {3549Texture *texture = texture_owner.get_or_null(shared.texture);3550ERR_CONTINUE(texture == nullptr);3551_texture_update_shared_fallback(shared.texture, texture, shared.writing);3552}3553}35543555RID RenderingDevice::uniform_set_create(const VectorView<RD::Uniform> &p_uniforms, RID p_shader, uint32_t p_shader_set, bool p_linear_pool) {3556_THREAD_SAFE_METHOD_35573558ERR_FAIL_COND_V(p_uniforms.size() == 0, RID());35593560Shader *shader = shader_owner.get_or_null(p_shader);3561ERR_FAIL_NULL_V(shader, RID());35623563ERR_FAIL_COND_V_MSG(p_shader_set >= (uint32_t)shader->uniform_sets.size() || shader->uniform_sets[p_shader_set].is_empty(), RID(),3564"Desired set (" + itos(p_shader_set) + ") not used by shader.");3565// See that all sets in shader are satisfied.35663567const Vector<ShaderUniform> &set = shader->uniform_sets[p_shader_set];35683569uint32_t uniform_count = p_uniforms.size();3570const Uniform *uniforms = p_uniforms.ptr();35713572uint32_t set_uniform_count = set.size();3573const ShaderUniform *set_uniforms = set.ptr();35743575LocalVector<RDD::BoundUniform> driver_uniforms;3576driver_uniforms.resize(set_uniform_count);35773578// Used for verification to make sure a uniform set does not use a framebuffer bound texture.3579LocalVector<UniformSet::AttachableTexture> attachable_textures;3580Vector<RDG::ResourceTracker *> draw_trackers;3581Vector<RDG::ResourceUsage> draw_trackers_usage;3582HashMap<RID, RDG::ResourceUsage> untracked_usage;3583Vector<UniformSet::SharedTexture> shared_textures_to_update;35843585for (uint32_t i = 0; i < set_uniform_count; i++) {3586const ShaderUniform &set_uniform = set_uniforms[i];3587int uniform_idx = -1;3588for (int j = 0; j < (int)uniform_count; j++) {3589if (uniforms[j].binding == set_uniform.binding) {3590uniform_idx = j;3591break;3592}3593}3594ERR_FAIL_COND_V_MSG(uniform_idx == -1, RID(),3595"All the shader bindings for the given set must be covered by the uniforms provided. Binding (" + itos(set_uniform.binding) + "), set (" + itos(p_shader_set) + ") was not provided.");35963597const Uniform &uniform = uniforms[uniform_idx];35983599ERR_FAIL_INDEX_V(uniform.uniform_type, RD::UNIFORM_TYPE_MAX, RID());3600ERR_FAIL_COND_V_MSG(uniform.uniform_type != set_uniform.type, RID(),3601"Mismatch uniform type for binding (" + itos(set_uniform.binding) + "), set (" + itos(p_shader_set) + "). Expected '" + SHADER_UNIFORM_NAMES[set_uniform.type] + "', supplied: '" + SHADER_UNIFORM_NAMES[uniform.uniform_type] + "'.");36023603RDD::BoundUniform &driver_uniform = driver_uniforms[i];3604driver_uniform.type = uniform.uniform_type;3605driver_uniform.binding = uniform.binding;36063607// Mark immutable samplers to be skipped when creating uniform set.3608driver_uniform.immutable_sampler = uniform.immutable_sampler;36093610switch (uniform.uniform_type) {3611case UNIFORM_TYPE_SAMPLER: {3612if (uniform.get_id_count() != (uint32_t)set_uniform.length) {3613if (set_uniform.length > 1) {3614ERR_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.get_id_count()) + ").");3615} else {3616ERR_FAIL_V_MSG(RID(), "Sampler (binding: " + itos(uniform.binding) + ") should provide one ID referencing a sampler (IDs provided: " + itos(uniform.get_id_count()) + ").");3617}3618}36193620for (uint32_t j = 0; j < uniform.get_id_count(); j++) {3621RDD::SamplerID *sampler_driver_id = sampler_owner.get_or_null(uniform.get_id(j));3622ERR_FAIL_NULL_V_MSG(sampler_driver_id, RID(), "Sampler (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") is not a valid sampler.");36233624driver_uniform.ids.push_back(*sampler_driver_id);3625}3626} break;3627case UNIFORM_TYPE_SAMPLER_WITH_TEXTURE: {3628if (uniform.get_id_count() != (uint32_t)set_uniform.length * 2) {3629if (set_uniform.length > 1) {3630ERR_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.get_id_count()) + ").");3631} else {3632ERR_FAIL_V_MSG(RID(), "SamplerTexture (binding: " + itos(uniform.binding) + ") should provide two IDs referencing a sampler and then a texture (IDs provided: " + itos(uniform.get_id_count()) + ").");3633}3634}36353636for (uint32_t j = 0; j < uniform.get_id_count(); j += 2) {3637RDD::SamplerID *sampler_driver_id = sampler_owner.get_or_null(uniform.get_id(j + 0));3638ERR_FAIL_NULL_V_MSG(sampler_driver_id, RID(), "SamplerBuffer (binding: " + itos(uniform.binding) + ", index " + itos(j + 1) + ") is not a valid sampler.");36393640RID texture_id = uniform.get_id(j + 1);3641Texture *texture = texture_owner.get_or_null(texture_id);3642ERR_FAIL_NULL_V_MSG(texture, RID(), "Texture (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") is not a valid texture.");36433644ERR_FAIL_COND_V_MSG(!(texture->usage_flags & TEXTURE_USAGE_SAMPLING_BIT), RID(),3645"Texture (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") needs the TEXTURE_USAGE_SAMPLING_BIT usage flag set in order to be used as uniform.");36463647if ((texture->usage_flags & (TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | TEXTURE_USAGE_INPUT_ATTACHMENT_BIT))) {3648UniformSet::AttachableTexture attachable_texture;3649attachable_texture.bind = set_uniform.binding;3650attachable_texture.texture = texture->owner.is_valid() ? texture->owner : uniform.get_id(j + 1);3651attachable_textures.push_back(attachable_texture);3652}36533654RDD::TextureID driver_id = texture->driver_id;3655RDG::ResourceTracker *tracker = texture->draw_tracker;3656if (texture->shared_fallback != nullptr && texture->shared_fallback->texture.id != 0) {3657driver_id = texture->shared_fallback->texture;3658tracker = texture->shared_fallback->texture_tracker;3659shared_textures_to_update.push_back({ false, texture_id });3660}36613662if (tracker != nullptr) {3663draw_trackers.push_back(tracker);3664draw_trackers_usage.push_back(RDG::RESOURCE_USAGE_TEXTURE_SAMPLE);3665} else {3666untracked_usage[texture_id] = RDG::RESOURCE_USAGE_TEXTURE_SAMPLE;3667}36683669DEV_ASSERT(!texture->owner.is_valid() || texture_owner.get_or_null(texture->owner));36703671driver_uniform.ids.push_back(*sampler_driver_id);3672driver_uniform.ids.push_back(driver_id);3673_check_transfer_worker_texture(texture);3674}3675} break;3676case UNIFORM_TYPE_TEXTURE: {3677if (uniform.get_id_count() != (uint32_t)set_uniform.length) {3678if (set_uniform.length > 1) {3679ERR_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.get_id_count()) + ").");3680} else {3681ERR_FAIL_V_MSG(RID(), "Texture (binding: " + itos(uniform.binding) + ") should provide one ID referencing a texture (IDs provided: " + itos(uniform.get_id_count()) + ").");3682}3683}36843685for (uint32_t j = 0; j < uniform.get_id_count(); j++) {3686RID texture_id = uniform.get_id(j);3687Texture *texture = texture_owner.get_or_null(texture_id);3688ERR_FAIL_NULL_V_MSG(texture, RID(), "Texture (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") is not a valid texture.");36893690ERR_FAIL_COND_V_MSG(!(texture->usage_flags & TEXTURE_USAGE_SAMPLING_BIT), RID(),3691"Texture (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") needs the TEXTURE_USAGE_SAMPLING_BIT usage flag set in order to be used as uniform.");36923693if ((texture->usage_flags & (TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | TEXTURE_USAGE_INPUT_ATTACHMENT_BIT))) {3694UniformSet::AttachableTexture attachable_texture;3695attachable_texture.bind = set_uniform.binding;3696attachable_texture.texture = texture->owner.is_valid() ? texture->owner : uniform.get_id(j);3697attachable_textures.push_back(attachable_texture);3698}36993700RDD::TextureID driver_id = texture->driver_id;3701RDG::ResourceTracker *tracker = texture->draw_tracker;3702if (texture->shared_fallback != nullptr && texture->shared_fallback->texture.id != 0) {3703driver_id = texture->shared_fallback->texture;3704tracker = texture->shared_fallback->texture_tracker;3705shared_textures_to_update.push_back({ false, texture_id });3706}37073708if (tracker != nullptr) {3709draw_trackers.push_back(tracker);3710draw_trackers_usage.push_back(RDG::RESOURCE_USAGE_TEXTURE_SAMPLE);3711} else {3712untracked_usage[texture_id] = RDG::RESOURCE_USAGE_TEXTURE_SAMPLE;3713}37143715DEV_ASSERT(!texture->owner.is_valid() || texture_owner.get_or_null(texture->owner));37163717driver_uniform.ids.push_back(driver_id);3718_check_transfer_worker_texture(texture);3719}3720} break;3721case UNIFORM_TYPE_IMAGE: {3722if (uniform.get_id_count() != (uint32_t)set_uniform.length) {3723if (set_uniform.length > 1) {3724ERR_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.get_id_count()) + ").");3725} else {3726ERR_FAIL_V_MSG(RID(), "Image (binding: " + itos(uniform.binding) + ") should provide one ID referencing a texture (IDs provided: " + itos(uniform.get_id_count()) + ").");3727}3728}37293730for (uint32_t j = 0; j < uniform.get_id_count(); j++) {3731RID texture_id = uniform.get_id(j);3732Texture *texture = texture_owner.get_or_null(texture_id);37333734ERR_FAIL_NULL_V_MSG(texture, RID(),3735"Image (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") is not a valid texture.");37363737ERR_FAIL_COND_V_MSG(!(texture->usage_flags & TEXTURE_USAGE_STORAGE_BIT), RID(),3738"Image (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") needs the TEXTURE_USAGE_STORAGE_BIT usage flag set in order to be used as uniform.");37393740if (texture->owner.is_null() && texture->shared_fallback != nullptr) {3741shared_textures_to_update.push_back({ true, texture_id });3742}37433744if (_texture_make_mutable(texture, texture_id)) {3745// The texture must be mutable as a layout transition will be required.3746draw_graph.add_synchronization();3747}37483749if (texture->draw_tracker != nullptr) {3750draw_trackers.push_back(texture->draw_tracker);37513752if (set_uniform.writable) {3753draw_trackers_usage.push_back(RDG::RESOURCE_USAGE_STORAGE_IMAGE_READ_WRITE);3754} else {3755draw_trackers_usage.push_back(RDG::RESOURCE_USAGE_STORAGE_IMAGE_READ);3756}3757}37583759DEV_ASSERT(!texture->owner.is_valid() || texture_owner.get_or_null(texture->owner));37603761driver_uniform.ids.push_back(texture->driver_id);3762_check_transfer_worker_texture(texture);3763}3764} break;3765case UNIFORM_TYPE_TEXTURE_BUFFER: {3766if (uniform.get_id_count() != (uint32_t)set_uniform.length) {3767if (set_uniform.length > 1) {3768ERR_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.get_id_count()) + ").");3769} else {3770ERR_FAIL_V_MSG(RID(), "Buffer (binding: " + itos(uniform.binding) + ") should provide one ID referencing a texture buffer (IDs provided: " + itos(uniform.get_id_count()) + ").");3771}3772}37733774for (uint32_t j = 0; j < uniform.get_id_count(); j++) {3775RID buffer_id = uniform.get_id(j);3776Buffer *buffer = texture_buffer_owner.get_or_null(buffer_id);3777ERR_FAIL_NULL_V_MSG(buffer, RID(), "Texture Buffer (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") is not a valid texture buffer.");37783779if (set_uniform.writable && _buffer_make_mutable(buffer, buffer_id)) {3780// The buffer must be mutable if it's used for writing.3781draw_graph.add_synchronization();3782}37833784if (buffer->draw_tracker != nullptr) {3785draw_trackers.push_back(buffer->draw_tracker);37863787if (set_uniform.writable) {3788draw_trackers_usage.push_back(RDG::RESOURCE_USAGE_TEXTURE_BUFFER_READ_WRITE);3789} else {3790draw_trackers_usage.push_back(RDG::RESOURCE_USAGE_TEXTURE_BUFFER_READ);3791}3792} else {3793untracked_usage[buffer_id] = RDG::RESOURCE_USAGE_TEXTURE_BUFFER_READ;3794}37953796driver_uniform.ids.push_back(buffer->driver_id);3797_check_transfer_worker_buffer(buffer);3798}3799} break;3800case UNIFORM_TYPE_SAMPLER_WITH_TEXTURE_BUFFER: {3801if (uniform.get_id_count() != (uint32_t)set_uniform.length * 2) {3802if (set_uniform.length > 1) {3803ERR_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.get_id_count()) + ").");3804} else {3805ERR_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.get_id_count()) + ").");3806}3807}38083809for (uint32_t j = 0; j < uniform.get_id_count(); j += 2) {3810RDD::SamplerID *sampler_driver_id = sampler_owner.get_or_null(uniform.get_id(j + 0));3811ERR_FAIL_NULL_V_MSG(sampler_driver_id, RID(), "SamplerBuffer (binding: " + itos(uniform.binding) + ", index " + itos(j + 1) + ") is not a valid sampler.");38123813RID buffer_id = uniform.get_id(j + 1);3814Buffer *buffer = texture_buffer_owner.get_or_null(buffer_id);3815ERR_FAIL_NULL_V_MSG(buffer, RID(), "SamplerBuffer (binding: " + itos(uniform.binding) + ", index " + itos(j + 1) + ") is not a valid texture buffer.");38163817if (buffer->draw_tracker != nullptr) {3818draw_trackers.push_back(buffer->draw_tracker);3819draw_trackers_usage.push_back(RDG::RESOURCE_USAGE_TEXTURE_BUFFER_READ);3820} else {3821untracked_usage[buffer_id] = RDG::RESOURCE_USAGE_TEXTURE_BUFFER_READ;3822}38233824driver_uniform.ids.push_back(*sampler_driver_id);3825driver_uniform.ids.push_back(buffer->driver_id);3826_check_transfer_worker_buffer(buffer);3827}3828} break;3829case UNIFORM_TYPE_IMAGE_BUFFER: {3830// Todo.3831} break;3832case UNIFORM_TYPE_UNIFORM_BUFFER: {3833ERR_FAIL_COND_V_MSG(uniform.get_id_count() != 1, RID(),3834"Uniform buffer supplied (binding: " + itos(uniform.binding) + ") must provide one ID (" + itos(uniform.get_id_count()) + " provided).");38353836RID buffer_id = uniform.get_id(0);3837Buffer *buffer = uniform_buffer_owner.get_or_null(buffer_id);3838ERR_FAIL_NULL_V_MSG(buffer, RID(), "Uniform buffer supplied (binding: " + itos(uniform.binding) + ") is invalid.");38393840ERR_FAIL_COND_V_MSG(buffer->size < (uint32_t)set_uniform.length, RID(),3841"Uniform buffer supplied (binding: " + itos(uniform.binding) + ") size (" + itos(buffer->size) + ") is smaller than size of shader uniform: (" + itos(set_uniform.length) + ").");38423843if (buffer->draw_tracker != nullptr) {3844draw_trackers.push_back(buffer->draw_tracker);3845draw_trackers_usage.push_back(RDG::RESOURCE_USAGE_UNIFORM_BUFFER_READ);3846} else {3847untracked_usage[buffer_id] = RDG::RESOURCE_USAGE_UNIFORM_BUFFER_READ;3848}38493850driver_uniform.ids.push_back(buffer->driver_id);3851_check_transfer_worker_buffer(buffer);3852} break;3853case UNIFORM_TYPE_STORAGE_BUFFER: {3854ERR_FAIL_COND_V_MSG(uniform.get_id_count() != 1, RID(),3855"Storage buffer supplied (binding: " + itos(uniform.binding) + ") must provide one ID (" + itos(uniform.get_id_count()) + " provided).");38563857Buffer *buffer = nullptr;38583859RID buffer_id = uniform.get_id(0);3860if (storage_buffer_owner.owns(buffer_id)) {3861buffer = storage_buffer_owner.get_or_null(buffer_id);3862} else if (vertex_buffer_owner.owns(buffer_id)) {3863buffer = vertex_buffer_owner.get_or_null(buffer_id);38643865ERR_FAIL_COND_V_MSG(!(buffer->usage.has_flag(RDD::BUFFER_USAGE_STORAGE_BIT)), RID(), "Vertex buffer supplied (binding: " + itos(uniform.binding) + ") was not created with storage flag.");3866}3867ERR_FAIL_NULL_V_MSG(buffer, RID(), "Storage buffer supplied (binding: " + itos(uniform.binding) + ") is invalid.");38683869// If 0, then it's sized on link time.3870ERR_FAIL_COND_V_MSG(set_uniform.length > 0 && buffer->size != (uint32_t)set_uniform.length, RID(),3871"Storage buffer supplied (binding: " + itos(uniform.binding) + ") size (" + itos(buffer->size) + ") does not match size of shader uniform: (" + itos(set_uniform.length) + ").");38723873if (set_uniform.writable && _buffer_make_mutable(buffer, buffer_id)) {3874// The buffer must be mutable if it's used for writing.3875draw_graph.add_synchronization();3876}38773878if (buffer->draw_tracker != nullptr) {3879draw_trackers.push_back(buffer->draw_tracker);38803881if (set_uniform.writable) {3882draw_trackers_usage.push_back(RDG::RESOURCE_USAGE_STORAGE_BUFFER_READ_WRITE);3883} else {3884draw_trackers_usage.push_back(RDG::RESOURCE_USAGE_STORAGE_BUFFER_READ);3885}3886} else {3887untracked_usage[buffer_id] = RDG::RESOURCE_USAGE_STORAGE_BUFFER_READ;3888}38893890driver_uniform.ids.push_back(buffer->driver_id);3891_check_transfer_worker_buffer(buffer);3892} break;3893case UNIFORM_TYPE_INPUT_ATTACHMENT: {3894ERR_FAIL_COND_V_MSG(shader->is_compute, RID(), "InputAttachment (binding: " + itos(uniform.binding) + ") supplied for compute shader (this is not allowed).");38953896if (uniform.get_id_count() != (uint32_t)set_uniform.length) {3897if (set_uniform.length > 1) {3898ERR_FAIL_V_MSG(RID(), "InputAttachment (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.get_id_count()) + ").");3899} else {3900ERR_FAIL_V_MSG(RID(), "InputAttachment (binding: " + itos(uniform.binding) + ") should provide one ID referencing a texture (IDs provided: " + itos(uniform.get_id_count()) + ").");3901}3902}39033904for (uint32_t j = 0; j < uniform.get_id_count(); j++) {3905RID texture_id = uniform.get_id(j);3906Texture *texture = texture_owner.get_or_null(texture_id);39073908ERR_FAIL_NULL_V_MSG(texture, RID(),3909"InputAttachment (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") is not a valid texture.");39103911ERR_FAIL_COND_V_MSG(!(texture->usage_flags & TEXTURE_USAGE_SAMPLING_BIT), RID(),3912"InputAttachment (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") needs the TEXTURE_USAGE_SAMPLING_BIT usage flag set in order to be used as uniform.");39133914DEV_ASSERT(!texture->owner.is_valid() || texture_owner.get_or_null(texture->owner));39153916driver_uniform.ids.push_back(texture->driver_id);3917_check_transfer_worker_texture(texture);3918}3919} break;3920default: {3921}3922}3923}39243925RDD::UniformSetID driver_uniform_set = driver->uniform_set_create(driver_uniforms, shader->driver_id, p_shader_set, p_linear_pool ? frame : -1);3926ERR_FAIL_COND_V(!driver_uniform_set, RID());39273928UniformSet uniform_set;3929uniform_set.driver_id = driver_uniform_set;3930uniform_set.format = shader->set_formats[p_shader_set];3931uniform_set.attachable_textures = attachable_textures;3932uniform_set.draw_trackers = draw_trackers;3933uniform_set.draw_trackers_usage = draw_trackers_usage;3934uniform_set.untracked_usage = untracked_usage;3935uniform_set.shared_textures_to_update = shared_textures_to_update;3936uniform_set.shader_set = p_shader_set;3937uniform_set.shader_id = p_shader;39383939RID id = uniform_set_owner.make_rid(uniform_set);3940#ifdef DEV_ENABLED3941set_resource_name(id, "RID:" + itos(id.get_id()));3942#endif3943// Add dependencies.3944_add_dependency(id, p_shader);3945for (uint32_t i = 0; i < uniform_count; i++) {3946const Uniform &uniform = uniforms[i];3947int id_count = uniform.get_id_count();3948for (int j = 0; j < id_count; j++) {3949_add_dependency(id, uniform.get_id(j));3950}3951}39523953return id;3954}39553956bool RenderingDevice::uniform_set_is_valid(RID p_uniform_set) {3957_THREAD_SAFE_METHOD_39583959return uniform_set_owner.owns(p_uniform_set);3960}39613962void RenderingDevice::uniform_set_set_invalidation_callback(RID p_uniform_set, InvalidationCallback p_callback, void *p_userdata) {3963_THREAD_SAFE_METHOD_39643965UniformSet *us = uniform_set_owner.get_or_null(p_uniform_set);3966ERR_FAIL_NULL(us);3967us->invalidated_callback = p_callback;3968us->invalidated_callback_userdata = p_userdata;3969}39703971bool RenderingDevice::uniform_sets_have_linear_pools() const {3972return driver->uniform_sets_have_linear_pools();3973}39743975/*******************/3976/**** PIPELINES ****/3977/*******************/39783979RID RenderingDevice::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, BitField<PipelineDynamicStateFlags> p_dynamic_state_flags, uint32_t p_for_render_pass, const Vector<PipelineSpecializationConstant> &p_specialization_constants) {3980// Needs a shader.3981Shader *shader = shader_owner.get_or_null(p_shader);3982ERR_FAIL_NULL_V(shader, RID());3983ERR_FAIL_COND_V_MSG(shader->is_compute, RID(), "Compute shaders can't be used in render pipelines");39843985// Validate pre-raster shader. One of stages must be vertex shader or mesh shader (not implemented yet).3986ERR_FAIL_COND_V_MSG(!shader->stage_bits.has_flag(RDD::PIPELINE_STAGE_VERTEX_SHADER_BIT), RID(), "Pre-raster shader (vertex shader) is not provided for pipeline creation.");39873988FramebufferFormat fb_format;3989{3990_THREAD_SAFE_METHOD_39913992if (p_framebuffer_format == INVALID_ID) {3993// If nothing provided, use an empty one (no attachments).3994p_framebuffer_format = framebuffer_format_create(Vector<AttachmentFormat>());3995}3996ERR_FAIL_COND_V(!framebuffer_formats.has(p_framebuffer_format), RID());3997fb_format = framebuffer_formats[p_framebuffer_format];3998}39994000// Validate shader vs. framebuffer.4001{4002ERR_FAIL_COND_V_MSG(p_for_render_pass >= uint32_t(fb_format.E->key().passes.size()), RID(), "Render pass requested for pipeline creation (" + itos(p_for_render_pass) + ") is out of bounds");4003const FramebufferPass &pass = fb_format.E->key().passes[p_for_render_pass];4004uint32_t output_mask = 0;4005for (int i = 0; i < pass.color_attachments.size(); i++) {4006if (pass.color_attachments[i] != ATTACHMENT_UNUSED) {4007output_mask |= 1 << i;4008}4009}4010ERR_FAIL_COND_V_MSG(shader->fragment_output_mask != output_mask, RID(),4011"Mismatch fragment shader output mask (" + itos(shader->fragment_output_mask) + ") and framebuffer color output mask (" + itos(output_mask) + ") when binding both in render pipeline.");4012}40134014RDD::VertexFormatID driver_vertex_format;4015if (p_vertex_format != INVALID_ID) {4016// Uses vertices, else it does not.4017ERR_FAIL_COND_V(!vertex_formats.has(p_vertex_format), RID());4018const VertexDescriptionCache &vd = vertex_formats[p_vertex_format];4019driver_vertex_format = vertex_formats[p_vertex_format].driver_id;40204021// Validate with inputs.4022for (uint32_t i = 0; i < 64; i++) {4023if (!(shader->vertex_input_mask & ((uint64_t)1) << i)) {4024continue;4025}4026bool found = false;4027for (int j = 0; j < vd.vertex_formats.size(); j++) {4028if (vd.vertex_formats[j].location == i) {4029found = true;4030break;4031}4032}40334034ERR_FAIL_COND_V_MSG(!found, RID(),4035"Shader vertex input location (" + itos(i) + ") not provided in vertex input description for pipeline creation.");4036}40374038} else {4039ERR_FAIL_COND_V_MSG(shader->vertex_input_mask != 0, RID(),4040"Shader contains vertex inputs, but no vertex input description was provided for pipeline creation.");4041}40424043ERR_FAIL_INDEX_V(p_render_primitive, RENDER_PRIMITIVE_MAX, RID());40444045ERR_FAIL_INDEX_V(p_rasterization_state.cull_mode, 3, RID());40464047if (p_multisample_state.sample_mask.size()) {4048// Use sample mask.4049ERR_FAIL_COND_V((int)TEXTURE_SAMPLES_COUNT[p_multisample_state.sample_count] != p_multisample_state.sample_mask.size(), RID());4050}40514052ERR_FAIL_INDEX_V(p_depth_stencil_state.depth_compare_operator, COMPARE_OP_MAX, RID());40534054ERR_FAIL_INDEX_V(p_depth_stencil_state.front_op.fail, STENCIL_OP_MAX, RID());4055ERR_FAIL_INDEX_V(p_depth_stencil_state.front_op.pass, STENCIL_OP_MAX, RID());4056ERR_FAIL_INDEX_V(p_depth_stencil_state.front_op.depth_fail, STENCIL_OP_MAX, RID());4057ERR_FAIL_INDEX_V(p_depth_stencil_state.front_op.compare, COMPARE_OP_MAX, RID());40584059ERR_FAIL_INDEX_V(p_depth_stencil_state.back_op.fail, STENCIL_OP_MAX, RID());4060ERR_FAIL_INDEX_V(p_depth_stencil_state.back_op.pass, STENCIL_OP_MAX, RID());4061ERR_FAIL_INDEX_V(p_depth_stencil_state.back_op.depth_fail, STENCIL_OP_MAX, RID());4062ERR_FAIL_INDEX_V(p_depth_stencil_state.back_op.compare, COMPARE_OP_MAX, RID());40634064ERR_FAIL_INDEX_V(p_blend_state.logic_op, LOGIC_OP_MAX, RID());40654066const FramebufferPass &pass = fb_format.E->key().passes[p_for_render_pass];4067ERR_FAIL_COND_V(p_blend_state.attachments.size() < pass.color_attachments.size(), RID());4068for (int i = 0; i < pass.color_attachments.size(); i++) {4069if (pass.color_attachments[i] != ATTACHMENT_UNUSED) {4070ERR_FAIL_INDEX_V(p_blend_state.attachments[i].src_color_blend_factor, BLEND_FACTOR_MAX, RID());4071ERR_FAIL_INDEX_V(p_blend_state.attachments[i].dst_color_blend_factor, BLEND_FACTOR_MAX, RID());4072ERR_FAIL_INDEX_V(p_blend_state.attachments[i].color_blend_op, BLEND_OP_MAX, RID());40734074ERR_FAIL_INDEX_V(p_blend_state.attachments[i].src_alpha_blend_factor, BLEND_FACTOR_MAX, RID());4075ERR_FAIL_INDEX_V(p_blend_state.attachments[i].dst_alpha_blend_factor, BLEND_FACTOR_MAX, RID());4076ERR_FAIL_INDEX_V(p_blend_state.attachments[i].alpha_blend_op, BLEND_OP_MAX, RID());4077}4078}40794080for (int i = 0; i < shader->specialization_constants.size(); i++) {4081const ShaderSpecializationConstant &sc = shader->specialization_constants[i];4082for (int j = 0; j < p_specialization_constants.size(); j++) {4083const PipelineSpecializationConstant &psc = p_specialization_constants[j];4084if (psc.constant_id == sc.constant_id) {4085ERR_FAIL_COND_V_MSG(psc.type != sc.type, RID(), "Specialization constant provided for id (" + itos(sc.constant_id) + ") is of the wrong type.");4086break;4087}4088}4089}40904091RenderPipeline pipeline;4092pipeline.driver_id = driver->render_pipeline_create(4093shader->driver_id,4094driver_vertex_format,4095p_render_primitive,4096p_rasterization_state,4097p_multisample_state,4098p_depth_stencil_state,4099p_blend_state,4100pass.color_attachments,4101p_dynamic_state_flags,4102fb_format.render_pass,4103p_for_render_pass,4104p_specialization_constants);4105ERR_FAIL_COND_V(!pipeline.driver_id, RID());41064107if (pipeline_cache_enabled) {4108_update_pipeline_cache();4109}41104111pipeline.shader = p_shader;4112pipeline.shader_driver_id = shader->driver_id;4113pipeline.shader_layout_hash = shader->layout_hash;4114pipeline.set_formats = shader->set_formats;4115pipeline.push_constant_size = shader->push_constant_size;4116pipeline.stage_bits = shader->stage_bits;41174118#ifdef DEBUG_ENABLED4119pipeline.validation.dynamic_state = p_dynamic_state_flags;4120pipeline.validation.framebuffer_format = p_framebuffer_format;4121pipeline.validation.render_pass = p_for_render_pass;4122pipeline.validation.vertex_format = p_vertex_format;4123pipeline.validation.uses_restart_indices = p_render_primitive == RENDER_PRIMITIVE_TRIANGLE_STRIPS_WITH_RESTART_INDEX;41244125static const uint32_t primitive_divisor[RENDER_PRIMITIVE_MAX] = {41261, 2, 1, 1, 1, 3, 1, 1, 1, 1, 14127};4128pipeline.validation.primitive_divisor = primitive_divisor[p_render_primitive];4129static const uint32_t primitive_minimum[RENDER_PRIMITIVE_MAX] = {41301,41312,41322,41332,41342,41353,41363,41373,41383,41393,41401,4141};4142pipeline.validation.primitive_minimum = primitive_minimum[p_render_primitive];4143#endif41444145// Create ID to associate with this pipeline.4146RID id = render_pipeline_owner.make_rid(pipeline);4147{4148_THREAD_SAFE_METHOD_41494150#ifdef DEV_ENABLED4151set_resource_name(id, "RID:" + itos(id.get_id()));4152#endif4153// Now add all the dependencies.4154_add_dependency(id, p_shader);4155}41564157return id;4158}41594160bool RenderingDevice::render_pipeline_is_valid(RID p_pipeline) {4161_THREAD_SAFE_METHOD_41624163return render_pipeline_owner.owns(p_pipeline);4164}41654166RID RenderingDevice::compute_pipeline_create(RID p_shader, const Vector<PipelineSpecializationConstant> &p_specialization_constants) {4167Shader *shader;41684169{4170_THREAD_SAFE_METHOD_41714172// Needs a shader.4173shader = shader_owner.get_or_null(p_shader);4174ERR_FAIL_NULL_V(shader, RID());41754176ERR_FAIL_COND_V_MSG(!shader->is_compute, RID(),4177"Non-compute shaders can't be used in compute pipelines");4178}41794180for (int i = 0; i < shader->specialization_constants.size(); i++) {4181const ShaderSpecializationConstant &sc = shader->specialization_constants[i];4182for (int j = 0; j < p_specialization_constants.size(); j++) {4183const PipelineSpecializationConstant &psc = p_specialization_constants[j];4184if (psc.constant_id == sc.constant_id) {4185ERR_FAIL_COND_V_MSG(psc.type != sc.type, RID(), "Specialization constant provided for id (" + itos(sc.constant_id) + ") is of the wrong type.");4186break;4187}4188}4189}41904191ComputePipeline pipeline;4192pipeline.driver_id = driver->compute_pipeline_create(shader->driver_id, p_specialization_constants);4193ERR_FAIL_COND_V(!pipeline.driver_id, RID());41944195if (pipeline_cache_enabled) {4196_update_pipeline_cache();4197}41984199pipeline.shader = p_shader;4200pipeline.shader_driver_id = shader->driver_id;4201pipeline.shader_layout_hash = shader->layout_hash;4202pipeline.set_formats = shader->set_formats;4203pipeline.push_constant_size = shader->push_constant_size;4204pipeline.local_group_size[0] = shader->compute_local_size[0];4205pipeline.local_group_size[1] = shader->compute_local_size[1];4206pipeline.local_group_size[2] = shader->compute_local_size[2];42074208// Create ID to associate with this pipeline.4209RID id = compute_pipeline_owner.make_rid(pipeline);4210{4211_THREAD_SAFE_METHOD_42124213#ifdef DEV_ENABLED4214set_resource_name(id, "RID:" + itos(id.get_id()));4215#endif4216// Now add all the dependencies.4217_add_dependency(id, p_shader);4218}42194220return id;4221}42224223bool RenderingDevice::compute_pipeline_is_valid(RID p_pipeline) {4224_THREAD_SAFE_METHOD_42254226return compute_pipeline_owner.owns(p_pipeline);4227}42284229/****************/4230/**** SCREEN ****/4231/****************/42324233uint32_t RenderingDevice::_get_swap_chain_desired_count() const {4234return MAX(2U, uint32_t(GLOBAL_GET_CACHED(uint32_t, "rendering/rendering_device/vsync/swapchain_image_count")));4235}42364237Error RenderingDevice::screen_create(DisplayServer::WindowID p_screen) {4238_THREAD_SAFE_METHOD_42394240RenderingContextDriver::SurfaceID surface = context->surface_get_from_window(p_screen);4241ERR_FAIL_COND_V_MSG(surface == 0, ERR_CANT_CREATE, "A surface was not created for the screen.");42424243HashMap<DisplayServer::WindowID, RDD::SwapChainID>::ConstIterator it = screen_swap_chains.find(p_screen);4244ERR_FAIL_COND_V_MSG(it != screen_swap_chains.end(), ERR_CANT_CREATE, "A swap chain was already created for the screen.");42454246RDD::SwapChainID swap_chain = driver->swap_chain_create(surface);4247ERR_FAIL_COND_V_MSG(swap_chain.id == 0, ERR_CANT_CREATE, "Unable to create swap chain.");42484249screen_swap_chains[p_screen] = swap_chain;42504251return OK;4252}42534254Error RenderingDevice::screen_prepare_for_drawing(DisplayServer::WindowID p_screen) {4255_THREAD_SAFE_METHOD_42564257// After submitting work, acquire the swapchain image(s).4258HashMap<DisplayServer::WindowID, RDD::SwapChainID>::ConstIterator it = screen_swap_chains.find(p_screen);4259ERR_FAIL_COND_V_MSG(it == screen_swap_chains.end(), ERR_CANT_CREATE, "A swap chain was not created for the screen.");42604261// Erase the framebuffer corresponding to this screen from the map in case any of the operations fail.4262screen_framebuffers.erase(p_screen);42634264// If this frame has already queued this swap chain for presentation, we present it and remove it from the pending list.4265uint32_t to_present_index = 0;4266while (to_present_index < frames[frame].swap_chains_to_present.size()) {4267if (frames[frame].swap_chains_to_present[to_present_index] == it->value) {4268driver->command_queue_execute_and_present(present_queue, {}, {}, {}, {}, it->value);4269frames[frame].swap_chains_to_present.remove_at(to_present_index);4270} else {4271to_present_index++;4272}4273}42744275bool resize_required = false;4276RDD::FramebufferID framebuffer = driver->swap_chain_acquire_framebuffer(main_queue, it->value, resize_required);4277if (resize_required) {4278// Flush everything so nothing can be using the swap chain before resizing it.4279_flush_and_stall_for_all_frames();42804281Error err = driver->swap_chain_resize(main_queue, it->value, _get_swap_chain_desired_count());4282if (err != OK) {4283// Resize is allowed to fail silently because the window can be minimized.4284return err;4285}42864287framebuffer = driver->swap_chain_acquire_framebuffer(main_queue, it->value, resize_required);4288}42894290if (framebuffer.id == 0) {4291// Some drivers like NVIDIA are fast enough to invalidate the swap chain between resizing and acquisition (GH-94104).4292// This typically occurs during continuous window resizing operations, especially if done quickly.4293// Allow this to fail silently since it has no visual consequences.4294return ERR_CANT_CREATE;4295}42964297// Store the framebuffer that will be used next to draw to this screen.4298screen_framebuffers[p_screen] = framebuffer;4299frames[frame].swap_chains_to_present.push_back(it->value);43004301return OK;4302}43034304int RenderingDevice::screen_get_width(DisplayServer::WindowID p_screen) const {4305_THREAD_SAFE_METHOD_43064307RenderingContextDriver::SurfaceID surface = context->surface_get_from_window(p_screen);4308ERR_FAIL_COND_V_MSG(surface == 0, 0, "A surface was not created for the screen.");4309return context->surface_get_width(surface);4310}43114312int RenderingDevice::screen_get_height(DisplayServer::WindowID p_screen) const {4313_THREAD_SAFE_METHOD_43144315RenderingContextDriver::SurfaceID surface = context->surface_get_from_window(p_screen);4316ERR_FAIL_COND_V_MSG(surface == 0, 0, "A surface was not created for the screen.");4317return context->surface_get_height(surface);4318}43194320int RenderingDevice::screen_get_pre_rotation_degrees(DisplayServer::WindowID p_screen) const {4321_THREAD_SAFE_METHOD_43224323HashMap<DisplayServer::WindowID, RDD::SwapChainID>::ConstIterator it = screen_swap_chains.find(p_screen);4324ERR_FAIL_COND_V_MSG(it == screen_swap_chains.end(), ERR_CANT_CREATE, "A swap chain was not created for the screen.");43254326return driver->swap_chain_get_pre_rotation_degrees(it->value);4327}43284329RenderingDevice::FramebufferFormatID RenderingDevice::screen_get_framebuffer_format(DisplayServer::WindowID p_screen) const {4330_THREAD_SAFE_METHOD_43314332HashMap<DisplayServer::WindowID, RDD::SwapChainID>::ConstIterator it = screen_swap_chains.find(p_screen);4333ERR_FAIL_COND_V_MSG(it == screen_swap_chains.end(), FAILED, "Screen was never prepared.");43344335DataFormat format = driver->swap_chain_get_format(it->value);4336ERR_FAIL_COND_V(format == DATA_FORMAT_MAX, INVALID_ID);43374338AttachmentFormat attachment;4339attachment.format = format;4340attachment.samples = TEXTURE_SAMPLES_1;4341attachment.usage_flags = TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;4342Vector<AttachmentFormat> screen_attachment;4343screen_attachment.push_back(attachment);4344return const_cast<RenderingDevice *>(this)->framebuffer_format_create(screen_attachment);4345}43464347Error RenderingDevice::screen_free(DisplayServer::WindowID p_screen) {4348_THREAD_SAFE_METHOD_43494350HashMap<DisplayServer::WindowID, RDD::SwapChainID>::ConstIterator it = screen_swap_chains.find(p_screen);4351ERR_FAIL_COND_V_MSG(it == screen_swap_chains.end(), FAILED, "Screen was never created.");43524353// Flush everything so nothing can be using the swap chain before erasing it.4354_flush_and_stall_for_all_frames();43554356const DisplayServer::WindowID screen = it->key;4357const RDD::SwapChainID swap_chain = it->value;4358driver->swap_chain_free(swap_chain);4359screen_framebuffers.erase(screen);4360screen_swap_chains.erase(screen);43614362return OK;4363}43644365/*******************/4366/**** DRAW LIST ****/4367/*******************/43684369RenderingDevice::DrawListID RenderingDevice::draw_list_begin_for_screen(DisplayServer::WindowID p_screen, const Color &p_clear_color) {4370ERR_RENDER_THREAD_GUARD_V(INVALID_ID);43714372ERR_FAIL_COND_V_MSG(draw_list.active, INVALID_ID, "Only one draw list can be active at the same time.");4373ERR_FAIL_COND_V_MSG(compute_list.active, INVALID_ID, "Only one draw/compute list can be active at the same time.");43744375RenderingContextDriver::SurfaceID surface = context->surface_get_from_window(p_screen);4376HashMap<DisplayServer::WindowID, RDD::SwapChainID>::ConstIterator sc_it = screen_swap_chains.find(p_screen);4377HashMap<DisplayServer::WindowID, RDD::FramebufferID>::ConstIterator fb_it = screen_framebuffers.find(p_screen);4378ERR_FAIL_COND_V_MSG(surface == 0, 0, "A surface was not created for the screen.");4379ERR_FAIL_COND_V_MSG(sc_it == screen_swap_chains.end(), INVALID_ID, "Screen was never prepared.");4380ERR_FAIL_COND_V_MSG(fb_it == screen_framebuffers.end(), INVALID_ID, "Framebuffer was never prepared.");43814382Rect2i viewport = Rect2i(0, 0, context->surface_get_width(surface), context->surface_get_height(surface));43834384_draw_list_start(viewport);4385#ifdef DEBUG_ENABLED4386draw_list_framebuffer_format = screen_get_framebuffer_format(p_screen);4387#endif4388draw_list_subpass_count = 1;43894390RDD::RenderPassClearValue clear_value;4391clear_value.color = p_clear_color;43924393RDD::RenderPassID render_pass = driver->swap_chain_get_render_pass(sc_it->value);4394draw_graph.add_draw_list_begin(render_pass, fb_it->value, viewport, RDG::ATTACHMENT_OPERATION_CLEAR, clear_value, RDD::PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, RDD::BreadcrumbMarker::BLIT_PASS, split_swapchain_into_its_own_cmd_buffer);43954396draw_graph.add_draw_list_set_viewport(viewport);4397draw_graph.add_draw_list_set_scissor(viewport);43984399return int64_t(ID_TYPE_DRAW_LIST) << ID_BASE_SHIFT;4400}44014402RenderingDevice::DrawListID RenderingDevice::_draw_list_begin_bind(RID p_framebuffer, BitField<DrawFlags> p_draw_flags, const Vector<Color> &p_clear_color_values, float p_clear_depth_value, uint32_t p_clear_stencil_value, const Rect2 &p_region, uint32_t p_breadcrumb) {4403return draw_list_begin(p_framebuffer, p_draw_flags, p_clear_color_values, p_clear_depth_value, p_clear_stencil_value, p_region, p_breadcrumb);4404}44054406RenderingDevice::DrawListID RenderingDevice::draw_list_begin(RID p_framebuffer, BitField<DrawFlags> p_draw_flags, VectorView<Color> p_clear_color_values, float p_clear_depth_value, uint32_t p_clear_stencil_value, const Rect2 &p_region, uint32_t p_breadcrumb) {4407ERR_RENDER_THREAD_GUARD_V(INVALID_ID);44084409ERR_FAIL_COND_V_MSG(draw_list.active, INVALID_ID, "Only one draw list can be active at the same time.");44104411Framebuffer *framebuffer = framebuffer_owner.get_or_null(p_framebuffer);4412ERR_FAIL_NULL_V(framebuffer, INVALID_ID);44134414const FramebufferFormatKey &framebuffer_key = framebuffer_formats[framebuffer->format_id].E->key();4415Point2i viewport_offset;4416Point2i viewport_size = framebuffer->size;44174418if (p_region != Rect2() && p_region != Rect2(Vector2(), viewport_size)) { // Check custom region.4419Rect2i viewport(viewport_offset, viewport_size);4420Rect2i regioni = p_region;4421if (!((regioni.position.x >= viewport.position.x) && (regioni.position.y >= viewport.position.y) &&4422((regioni.position.x + regioni.size.x) <= (viewport.position.x + viewport.size.x)) &&4423((regioni.position.y + regioni.size.y) <= (viewport.position.y + viewport.size.y)))) {4424ERR_FAIL_V_MSG(INVALID_ID, "When supplying a custom region, it must be contained within the framebuffer rectangle");4425}44264427viewport_offset = regioni.position;4428viewport_size = regioni.size;4429}44304431thread_local LocalVector<RDG::AttachmentOperation> operations;4432thread_local LocalVector<RDD::RenderPassClearValue> clear_values;4433thread_local LocalVector<RDG::ResourceTracker *> resource_trackers;4434thread_local LocalVector<RDG::ResourceUsage> resource_usages;4435BitField<RDD::PipelineStageBits> stages = {};4436operations.resize(framebuffer->texture_ids.size());4437clear_values.resize(framebuffer->texture_ids.size());4438resource_trackers.clear();4439resource_usages.clear();4440stages.clear();44414442uint32_t color_index = 0;4443for (int i = 0; i < framebuffer->texture_ids.size(); i++) {4444RID texture_rid = framebuffer->texture_ids[i];4445Texture *texture = texture_owner.get_or_null(texture_rid);4446if (texture == nullptr) {4447operations[i] = RDG::ATTACHMENT_OPERATION_DEFAULT;4448clear_values[i] = RDD::RenderPassClearValue();4449continue;4450}44514452// Indicate the texture will get modified for the shared texture fallback.4453_texture_update_shared_fallback(texture_rid, texture, true);44544455RDG::AttachmentOperation operation = RDG::ATTACHMENT_OPERATION_DEFAULT;4456RDD::RenderPassClearValue clear_value;4457if (framebuffer_key.vrs_attachment == i && (texture->usage_flags & TEXTURE_USAGE_VRS_ATTACHMENT_BIT)) {4458resource_trackers.push_back(texture->draw_tracker);4459resource_usages.push_back(_vrs_usage_from_method(framebuffer_key.vrs_method));4460stages.set_flag(_vrs_stages_from_method(framebuffer_key.vrs_method));4461} else if (texture->usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) {4462if (p_draw_flags.has_flag(DrawFlags(DRAW_CLEAR_COLOR_0 << color_index))) {4463ERR_FAIL_COND_V_MSG(color_index >= p_clear_color_values.size(), INVALID_ID, vformat("Color texture (%d) was specified to be cleared but no color value was provided.", color_index));4464operation = RDG::ATTACHMENT_OPERATION_CLEAR;4465clear_value.color = p_clear_color_values[color_index];4466} else if (p_draw_flags.has_flag(DrawFlags(DRAW_IGNORE_COLOR_0 << color_index))) {4467operation = RDG::ATTACHMENT_OPERATION_IGNORE;4468}44694470resource_trackers.push_back(texture->draw_tracker);4471resource_usages.push_back(RDG::RESOURCE_USAGE_ATTACHMENT_COLOR_READ_WRITE);4472stages.set_flag(RDD::PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);4473color_index++;4474} else if (texture->usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {4475if (p_draw_flags.has_flag(DRAW_CLEAR_DEPTH) || p_draw_flags.has_flag(DRAW_CLEAR_STENCIL)) {4476operation = RDG::ATTACHMENT_OPERATION_CLEAR;4477clear_value.depth = p_clear_depth_value;4478clear_value.stencil = p_clear_stencil_value;4479} else if (p_draw_flags.has_flag(DRAW_IGNORE_DEPTH) || p_draw_flags.has_flag(DRAW_IGNORE_STENCIL)) {4480operation = RDG::ATTACHMENT_OPERATION_IGNORE;4481}44824483resource_trackers.push_back(texture->draw_tracker);4484resource_usages.push_back(RDG::RESOURCE_USAGE_ATTACHMENT_DEPTH_STENCIL_READ_WRITE);4485stages.set_flag(RDD::PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT);4486stages.set_flag(RDD::PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT);4487}44884489operations[i] = operation;4490clear_values[i] = clear_value;4491}44924493draw_graph.add_draw_list_begin(framebuffer->framebuffer_cache, Rect2i(viewport_offset, viewport_size), operations, clear_values, stages, p_breadcrumb);4494draw_graph.add_draw_list_usages(resource_trackers, resource_usages);44954496// Mark textures as bound.4497draw_list_bound_textures.clear();44984499for (int i = 0; i < framebuffer->texture_ids.size(); i++) {4500Texture *texture = texture_owner.get_or_null(framebuffer->texture_ids[i]);4501if (texture == nullptr) {4502continue;4503}45044505texture->bound = true;4506draw_list_bound_textures.push_back(framebuffer->texture_ids[i]);4507}45084509_draw_list_start(Rect2i(viewport_offset, viewport_size));4510#ifdef DEBUG_ENABLED4511draw_list_framebuffer_format = framebuffer->format_id;4512#endif4513draw_list_current_subpass = 0;4514draw_list_subpass_count = framebuffer_key.passes.size();45154516Rect2i viewport_rect(viewport_offset, viewport_size);4517draw_graph.add_draw_list_set_viewport(viewport_rect);4518draw_graph.add_draw_list_set_scissor(viewport_rect);45194520return int64_t(ID_TYPE_DRAW_LIST) << ID_BASE_SHIFT;4521}45224523#ifndef DISABLE_DEPRECATED4524Error RenderingDevice::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, const Vector<RID> &p_storage_textures) {4525ERR_FAIL_V_MSG(ERR_UNAVAILABLE, "Deprecated. Split draw lists are used automatically by RenderingDevice.");4526}4527#endif45284529void RenderingDevice::draw_list_set_blend_constants(DrawListID p_list, const Color &p_color) {4530ERR_RENDER_THREAD_GUARD();45314532ERR_FAIL_COND(!draw_list.active);45334534draw_graph.add_draw_list_set_blend_constants(p_color);4535}45364537void RenderingDevice::draw_list_bind_render_pipeline(DrawListID p_list, RID p_render_pipeline) {4538ERR_RENDER_THREAD_GUARD();45394540ERR_FAIL_COND(!draw_list.active);45414542const RenderPipeline *pipeline = render_pipeline_owner.get_or_null(p_render_pipeline);4543ERR_FAIL_NULL(pipeline);4544#ifdef DEBUG_ENABLED4545ERR_FAIL_COND(pipeline->validation.framebuffer_format != draw_list_framebuffer_format && pipeline->validation.render_pass != draw_list_current_subpass);4546#endif45474548if (p_render_pipeline == draw_list.state.pipeline) {4549return; // Redundant state, return.4550}45514552draw_list.state.pipeline = p_render_pipeline;45534554draw_graph.add_draw_list_bind_pipeline(pipeline->driver_id, pipeline->stage_bits);45554556if (draw_list.state.pipeline_shader != pipeline->shader) {4557// Shader changed, so descriptor sets may become incompatible.45584559uint32_t pcount = pipeline->set_formats.size(); // Formats count in this pipeline.4560draw_list.state.set_count = MAX(draw_list.state.set_count, pcount);4561const uint32_t *pformats = pipeline->set_formats.ptr(); // Pipeline set formats.45624563uint32_t first_invalid_set = UINT32_MAX; // All valid by default.4564if (pipeline->push_constant_size != draw_list.state.pipeline_push_constant_size) {4565// All sets must be invalidated as the pipeline layout is not compatible if the push constant range is different.4566draw_list.state.pipeline_push_constant_size = pipeline->push_constant_size;4567first_invalid_set = 0;4568} else {4569switch (driver->api_trait_get(RDD::API_TRAIT_SHADER_CHANGE_INVALIDATION)) {4570case RDD::SHADER_CHANGE_INVALIDATION_ALL_BOUND_UNIFORM_SETS: {4571first_invalid_set = 0;4572} break;4573case RDD::SHADER_CHANGE_INVALIDATION_INCOMPATIBLE_SETS_PLUS_CASCADE: {4574for (uint32_t i = 0; i < pcount; i++) {4575if (draw_list.state.sets[i].pipeline_expected_format != pformats[i]) {4576first_invalid_set = i;4577break;4578}4579}4580} break;4581case RDD::SHADER_CHANGE_INVALIDATION_ALL_OR_NONE_ACCORDING_TO_LAYOUT_HASH: {4582if (draw_list.state.pipeline_shader_layout_hash != pipeline->shader_layout_hash) {4583first_invalid_set = 0;4584}4585} break;4586}4587}45884589if (pipeline->push_constant_size) {4590#ifdef DEBUG_ENABLED4591draw_list.validation.pipeline_push_constant_supplied = false;4592#endif4593}45944595for (uint32_t i = 0; i < pcount; i++) {4596draw_list.state.sets[i].bound = draw_list.state.sets[i].bound && i < first_invalid_set;4597draw_list.state.sets[i].pipeline_expected_format = pformats[i];4598}45994600for (uint32_t i = pcount; i < draw_list.state.set_count; i++) {4601// Unbind the ones above (not used) if exist.4602draw_list.state.sets[i].bound = false;4603}46044605draw_list.state.set_count = pcount; // Update set count.46064607draw_list.state.pipeline_shader = pipeline->shader;4608draw_list.state.pipeline_shader_driver_id = pipeline->shader_driver_id;4609draw_list.state.pipeline_shader_layout_hash = pipeline->shader_layout_hash;4610}46114612#ifdef DEBUG_ENABLED4613// Update render pass pipeline info.4614draw_list.validation.pipeline_active = true;4615draw_list.validation.pipeline_dynamic_state = pipeline->validation.dynamic_state;4616draw_list.validation.pipeline_vertex_format = pipeline->validation.vertex_format;4617draw_list.validation.pipeline_uses_restart_indices = pipeline->validation.uses_restart_indices;4618draw_list.validation.pipeline_primitive_divisor = pipeline->validation.primitive_divisor;4619draw_list.validation.pipeline_primitive_minimum = pipeline->validation.primitive_minimum;4620draw_list.validation.pipeline_push_constant_size = pipeline->push_constant_size;4621#endif4622}46234624void RenderingDevice::draw_list_bind_uniform_set(DrawListID p_list, RID p_uniform_set, uint32_t p_index) {4625ERR_RENDER_THREAD_GUARD();46264627#ifdef DEBUG_ENABLED4628ERR_FAIL_COND_MSG(p_index >= driver->limit_get(LIMIT_MAX_BOUND_UNIFORM_SETS) || p_index >= MAX_UNIFORM_SETS,4629"Attempting to bind a descriptor set (" + itos(p_index) + ") greater than what the hardware supports (" + itos(driver->limit_get(LIMIT_MAX_BOUND_UNIFORM_SETS)) + ").");4630#endif46314632ERR_FAIL_COND(!draw_list.active);46334634const UniformSet *uniform_set = uniform_set_owner.get_or_null(p_uniform_set);4635ERR_FAIL_NULL(uniform_set);46364637if (p_index > draw_list.state.set_count) {4638draw_list.state.set_count = p_index;4639}46404641draw_list.state.sets[p_index].uniform_set_driver_id = uniform_set->driver_id; // Update set pointer.4642draw_list.state.sets[p_index].bound = false; // Needs rebind.4643draw_list.state.sets[p_index].uniform_set_format = uniform_set->format;4644draw_list.state.sets[p_index].uniform_set = p_uniform_set;46454646#ifdef DEBUG_ENABLED4647{ // Validate that textures bound are not attached as framebuffer bindings.4648uint32_t attachable_count = uniform_set->attachable_textures.size();4649const UniformSet::AttachableTexture *attachable_ptr = uniform_set->attachable_textures.ptr();4650uint32_t bound_count = draw_list_bound_textures.size();4651const RID *bound_ptr = draw_list_bound_textures.ptr();4652for (uint32_t i = 0; i < attachable_count; i++) {4653for (uint32_t j = 0; j < bound_count; j++) {4654ERR_FAIL_COND_MSG(attachable_ptr[i].texture == bound_ptr[j],4655"Attempted to use the same texture in framebuffer attachment and a uniform (set: " + itos(p_index) + ", binding: " + itos(attachable_ptr[i].bind) + "), this is not allowed.");4656}4657}4658}4659#endif4660}46614662void RenderingDevice::draw_list_bind_vertex_array(DrawListID p_list, RID p_vertex_array) {4663ERR_RENDER_THREAD_GUARD();46644665ERR_FAIL_COND(!draw_list.active);46664667VertexArray *vertex_array = vertex_array_owner.get_or_null(p_vertex_array);4668ERR_FAIL_NULL(vertex_array);46694670if (draw_list.state.vertex_array == p_vertex_array) {4671return; // Already set.4672}46734674_check_transfer_worker_vertex_array(vertex_array);46754676draw_list.state.vertex_array = p_vertex_array;46774678#ifdef DEBUG_ENABLED4679draw_list.validation.vertex_format = vertex_array->description;4680draw_list.validation.vertex_max_instances_allowed = vertex_array->max_instances_allowed;4681#endif4682draw_list.validation.vertex_array_size = vertex_array->vertex_count;46834684draw_graph.add_draw_list_bind_vertex_buffers(vertex_array->buffers, vertex_array->offsets);46854686for (int i = 0; i < vertex_array->draw_trackers.size(); i++) {4687draw_graph.add_draw_list_usage(vertex_array->draw_trackers[i], RDG::RESOURCE_USAGE_VERTEX_BUFFER_READ);4688}4689}46904691void RenderingDevice::draw_list_bind_index_array(DrawListID p_list, RID p_index_array) {4692ERR_RENDER_THREAD_GUARD();46934694ERR_FAIL_COND(!draw_list.active);46954696IndexArray *index_array = index_array_owner.get_or_null(p_index_array);4697ERR_FAIL_NULL(index_array);46984699if (draw_list.state.index_array == p_index_array) {4700return; // Already set.4701}47024703_check_transfer_worker_index_array(index_array);47044705draw_list.state.index_array = p_index_array;4706#ifdef DEBUG_ENABLED4707draw_list.validation.index_array_max_index = index_array->max_index;4708#endif4709draw_list.validation.index_array_count = index_array->indices;47104711const uint64_t offset_bytes = index_array->offset * (index_array->format == INDEX_BUFFER_FORMAT_UINT16 ? sizeof(uint16_t) : sizeof(uint32_t));4712draw_graph.add_draw_list_bind_index_buffer(index_array->driver_id, index_array->format, offset_bytes);47134714if (index_array->draw_tracker != nullptr) {4715draw_graph.add_draw_list_usage(index_array->draw_tracker, RDG::RESOURCE_USAGE_INDEX_BUFFER_READ);4716}4717}47184719void RenderingDevice::draw_list_set_line_width(DrawListID p_list, float p_width) {4720ERR_RENDER_THREAD_GUARD();47214722ERR_FAIL_COND(!draw_list.active);47234724draw_graph.add_draw_list_set_line_width(p_width);4725}47264727void RenderingDevice::draw_list_set_push_constant(DrawListID p_list, const void *p_data, uint32_t p_data_size) {4728ERR_RENDER_THREAD_GUARD();47294730ERR_FAIL_COND(!draw_list.active);47314732#ifdef DEBUG_ENABLED4733ERR_FAIL_COND_MSG(p_data_size != draw_list.validation.pipeline_push_constant_size,4734"This render pipeline requires (" + itos(draw_list.validation.pipeline_push_constant_size) + ") bytes of push constant data, supplied: (" + itos(p_data_size) + ")");4735#endif47364737draw_graph.add_draw_list_set_push_constant(draw_list.state.pipeline_shader_driver_id, p_data, p_data_size);47384739#ifdef DEBUG_ENABLED4740draw_list.validation.pipeline_push_constant_supplied = true;4741#endif4742}47434744void RenderingDevice::draw_list_draw(DrawListID p_list, bool p_use_indices, uint32_t p_instances, uint32_t p_procedural_vertices) {4745ERR_RENDER_THREAD_GUARD();47464747ERR_FAIL_COND(!draw_list.active);47484749#ifdef DEBUG_ENABLED4750ERR_FAIL_COND_MSG(!draw_list.validation.pipeline_active,4751"No render pipeline was set before attempting to draw.");4752if (draw_list.validation.pipeline_vertex_format != INVALID_ID) {4753// Pipeline uses vertices, validate format.4754ERR_FAIL_COND_MSG(draw_list.validation.vertex_format == INVALID_ID,4755"No vertex array was bound, and render pipeline expects vertices.");4756// Make sure format is right.4757ERR_FAIL_COND_MSG(draw_list.validation.pipeline_vertex_format != draw_list.validation.vertex_format,4758"The vertex format used to create the pipeline does not match the vertex format bound.");4759// Make sure number of instances is valid.4760ERR_FAIL_COND_MSG(p_instances > draw_list.validation.vertex_max_instances_allowed,4761"Number of instances requested (" + itos(p_instances) + " is larger than the maximum number supported by the bound vertex array (" + itos(draw_list.validation.vertex_max_instances_allowed) + ").");4762}47634764if (draw_list.validation.pipeline_push_constant_size > 0) {4765// Using push constants, check that they were supplied.4766ERR_FAIL_COND_MSG(!draw_list.validation.pipeline_push_constant_supplied,4767"The shader in this pipeline requires a push constant to be set before drawing, but it's not present.");4768}47694770#endif47714772#ifdef DEBUG_ENABLED4773for (uint32_t i = 0; i < draw_list.state.set_count; i++) {4774if (draw_list.state.sets[i].pipeline_expected_format == 0) {4775// Nothing expected by this pipeline.4776continue;4777}47784779if (draw_list.state.sets[i].pipeline_expected_format != draw_list.state.sets[i].uniform_set_format) {4780if (draw_list.state.sets[i].uniform_set_format == 0) {4781ERR_FAIL_MSG("Uniforms were never supplied for set (" + itos(i) + ") at the time of drawing, which are required by the pipeline.");4782} else if (uniform_set_owner.owns(draw_list.state.sets[i].uniform_set)) {4783UniformSet *us = uniform_set_owner.get_or_null(draw_list.state.sets[i].uniform_set);4784ERR_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(draw_list.state.pipeline_shader));4785} else {4786ERR_FAIL_MSG("Uniforms supplied for set (" + itos(i) + ", which was just freed) are not the same format as required by the pipeline shader. Pipeline shader requires the following bindings:\n" + _shader_uniform_debug(draw_list.state.pipeline_shader));4787}4788}4789}4790#endif4791thread_local LocalVector<RDD::UniformSetID> valid_descriptor_ids;4792valid_descriptor_ids.clear();4793valid_descriptor_ids.resize(draw_list.state.set_count);4794uint32_t valid_set_count = 0;4795uint32_t first_set_index = 0;4796uint32_t last_set_index = 0;4797bool found_first_set = false;47984799for (uint32_t i = 0; i < draw_list.state.set_count; i++) {4800if (draw_list.state.sets[i].pipeline_expected_format == 0) {4801continue; // Nothing expected by this pipeline.4802}48034804if (!draw_list.state.sets[i].bound && !found_first_set) {4805first_set_index = i;4806found_first_set = true;4807}4808// Prepare descriptor sets if the API doesn't use pipeline barriers.4809if (!driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) {4810draw_graph.add_draw_list_uniform_set_prepare_for_use(draw_list.state.pipeline_shader_driver_id, draw_list.state.sets[i].uniform_set_driver_id, i);4811}4812}48134814// Bind descriptor sets.4815for (uint32_t i = first_set_index; i < draw_list.state.set_count; i++) {4816if (draw_list.state.sets[i].pipeline_expected_format == 0) {4817continue; // Nothing expected by this pipeline.4818}48194820if (!draw_list.state.sets[i].bound) {4821// Batch contiguous descriptor sets in a single call.4822if (descriptor_set_batching) {4823// All good, see if this requires re-binding.4824if (i - last_set_index > 1) {4825// If the descriptor sets are not contiguous, bind the previous ones and start a new batch.4826draw_graph.add_draw_list_bind_uniform_sets(draw_list.state.pipeline_shader_driver_id, valid_descriptor_ids, first_set_index, valid_set_count);48274828first_set_index = i;4829valid_set_count = 1;4830valid_descriptor_ids[0] = draw_list.state.sets[i].uniform_set_driver_id;4831} else {4832// Otherwise, keep storing in the current batch.4833valid_descriptor_ids[valid_set_count] = draw_list.state.sets[i].uniform_set_driver_id;4834valid_set_count++;4835}48364837UniformSet *uniform_set = uniform_set_owner.get_or_null(draw_list.state.sets[i].uniform_set);4838_uniform_set_update_shared(uniform_set);4839draw_graph.add_draw_list_usages(uniform_set->draw_trackers, uniform_set->draw_trackers_usage);4840draw_list.state.sets[i].bound = true;48414842last_set_index = i;4843} else {4844draw_graph.add_draw_list_bind_uniform_set(draw_list.state.pipeline_shader_driver_id, draw_list.state.sets[i].uniform_set_driver_id, i);4845}4846}4847}48484849// Bind the remaining batch.4850if (descriptor_set_batching && valid_set_count > 0) {4851draw_graph.add_draw_list_bind_uniform_sets(draw_list.state.pipeline_shader_driver_id, valid_descriptor_ids, first_set_index, valid_set_count);4852}48534854if (p_use_indices) {4855#ifdef DEBUG_ENABLED4856ERR_FAIL_COND_MSG(p_procedural_vertices > 0,4857"Procedural vertices can't be used together with indices.");48584859ERR_FAIL_COND_MSG(!draw_list.validation.index_array_count,4860"Draw command requested indices, but no index buffer was set.");48614862ERR_FAIL_COND_MSG(draw_list.validation.pipeline_uses_restart_indices != draw_list.validation.index_buffer_uses_restart_indices,4863"The usage of restart indices in index buffer does not match the render primitive in the pipeline.");4864#endif4865uint32_t to_draw = draw_list.validation.index_array_count;48664867#ifdef DEBUG_ENABLED4868ERR_FAIL_COND_MSG(to_draw < draw_list.validation.pipeline_primitive_minimum,4869"Too few indices (" + itos(to_draw) + ") for the render primitive set in the render pipeline (" + itos(draw_list.validation.pipeline_primitive_minimum) + ").");48704871ERR_FAIL_COND_MSG((to_draw % draw_list.validation.pipeline_primitive_divisor) != 0,4872"Index amount (" + itos(to_draw) + ") must be a multiple of the amount of indices required by the render primitive (" + itos(draw_list.validation.pipeline_primitive_divisor) + ").");4873#endif48744875draw_graph.add_draw_list_draw_indexed(to_draw, p_instances, 0);4876} else {4877uint32_t to_draw;48784879if (p_procedural_vertices > 0) {4880#ifdef DEBUG_ENABLED4881ERR_FAIL_COND_MSG(draw_list.validation.pipeline_vertex_format != INVALID_ID,4882"Procedural vertices requested, but pipeline expects a vertex array.");4883#endif4884to_draw = p_procedural_vertices;4885} else {4886#ifdef DEBUG_ENABLED4887ERR_FAIL_COND_MSG(draw_list.validation.pipeline_vertex_format == INVALID_ID,4888"Draw command lacks indices, but pipeline format does not use vertices.");4889#endif4890to_draw = draw_list.validation.vertex_array_size;4891}48924893#ifdef DEBUG_ENABLED4894ERR_FAIL_COND_MSG(to_draw < draw_list.validation.pipeline_primitive_minimum,4895"Too few vertices (" + itos(to_draw) + ") for the render primitive set in the render pipeline (" + itos(draw_list.validation.pipeline_primitive_minimum) + ").");48964897ERR_FAIL_COND_MSG((to_draw % draw_list.validation.pipeline_primitive_divisor) != 0,4898"Vertex amount (" + itos(to_draw) + ") must be a multiple of the amount of vertices required by the render primitive (" + itos(draw_list.validation.pipeline_primitive_divisor) + ").");4899#endif49004901draw_graph.add_draw_list_draw(to_draw, p_instances);4902}49034904draw_list.state.draw_count++;4905}49064907void RenderingDevice::draw_list_draw_indirect(DrawListID p_list, bool p_use_indices, RID p_buffer, uint32_t p_offset, uint32_t p_draw_count, uint32_t p_stride) {4908ERR_RENDER_THREAD_GUARD();49094910ERR_FAIL_COND(!draw_list.active);49114912Buffer *buffer = storage_buffer_owner.get_or_null(p_buffer);4913ERR_FAIL_NULL(buffer);49144915ERR_FAIL_COND_MSG(!buffer->usage.has_flag(RDD::BUFFER_USAGE_INDIRECT_BIT), "Buffer provided was not created to do indirect dispatch.");49164917#ifdef DEBUG_ENABLED4918ERR_FAIL_COND_MSG(!draw_list.validation.pipeline_active,4919"No render pipeline was set before attempting to draw.");4920if (draw_list.validation.pipeline_vertex_format != INVALID_ID) {4921// Pipeline uses vertices, validate format.4922ERR_FAIL_COND_MSG(draw_list.validation.vertex_format == INVALID_ID,4923"No vertex array was bound, and render pipeline expects vertices.");4924// Make sure format is right.4925ERR_FAIL_COND_MSG(draw_list.validation.pipeline_vertex_format != draw_list.validation.vertex_format,4926"The vertex format used to create the pipeline does not match the vertex format bound.");4927}49284929if (draw_list.validation.pipeline_push_constant_size > 0) {4930// Using push constants, check that they were supplied.4931ERR_FAIL_COND_MSG(!draw_list.validation.pipeline_push_constant_supplied,4932"The shader in this pipeline requires a push constant to be set before drawing, but it's not present.");4933}4934#endif49354936#ifdef DEBUG_ENABLED4937for (uint32_t i = 0; i < draw_list.state.set_count; i++) {4938if (draw_list.state.sets[i].pipeline_expected_format == 0) {4939// Nothing expected by this pipeline.4940continue;4941}49424943if (draw_list.state.sets[i].pipeline_expected_format != draw_list.state.sets[i].uniform_set_format) {4944if (draw_list.state.sets[i].uniform_set_format == 0) {4945ERR_FAIL_MSG(vformat("Uniforms were never supplied for set (%d) at the time of drawing, which are required by the pipeline.", i));4946} else if (uniform_set_owner.owns(draw_list.state.sets[i].uniform_set)) {4947UniformSet *us = uniform_set_owner.get_or_null(draw_list.state.sets[i].uniform_set);4948ERR_FAIL_MSG(vformat("Uniforms supplied for set (%d):\n%s\nare not the same format as required by the pipeline shader. Pipeline shader requires the following bindings:\n%s", i, _shader_uniform_debug(us->shader_id, us->shader_set), _shader_uniform_debug(draw_list.state.pipeline_shader)));4949} else {4950ERR_FAIL_MSG(vformat("Uniforms supplied for set (%s, which was just freed) are not the same format as required by the pipeline shader. Pipeline shader requires the following bindings:\n%s", i, _shader_uniform_debug(draw_list.state.pipeline_shader)));4951}4952}4953}4954#endif49554956// Prepare descriptor sets if the API doesn't use pipeline barriers.4957if (!driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) {4958for (uint32_t i = 0; i < draw_list.state.set_count; i++) {4959if (draw_list.state.sets[i].pipeline_expected_format == 0) {4960// Nothing expected by this pipeline.4961continue;4962}49634964draw_graph.add_draw_list_uniform_set_prepare_for_use(draw_list.state.pipeline_shader_driver_id, draw_list.state.sets[i].uniform_set_driver_id, i);4965}4966}49674968// Bind descriptor sets.4969for (uint32_t i = 0; i < draw_list.state.set_count; i++) {4970if (draw_list.state.sets[i].pipeline_expected_format == 0) {4971continue; // Nothing expected by this pipeline.4972}4973if (!draw_list.state.sets[i].bound) {4974// All good, see if this requires re-binding.4975draw_graph.add_draw_list_bind_uniform_set(draw_list.state.pipeline_shader_driver_id, draw_list.state.sets[i].uniform_set_driver_id, i);49764977UniformSet *uniform_set = uniform_set_owner.get_or_null(draw_list.state.sets[i].uniform_set);4978_uniform_set_update_shared(uniform_set);49794980draw_graph.add_draw_list_usages(uniform_set->draw_trackers, uniform_set->draw_trackers_usage);49814982draw_list.state.sets[i].bound = true;4983}4984}49854986if (p_use_indices) {4987#ifdef DEBUG_ENABLED4988ERR_FAIL_COND_MSG(!draw_list.validation.index_array_count,4989"Draw command requested indices, but no index buffer was set.");49904991ERR_FAIL_COND_MSG(draw_list.validation.pipeline_uses_restart_indices != draw_list.validation.index_buffer_uses_restart_indices,4992"The usage of restart indices in index buffer does not match the render primitive in the pipeline.");4993#endif49944995ERR_FAIL_COND_MSG(p_offset + 20 > buffer->size, "Offset provided (+20) is past the end of buffer.");49964997draw_graph.add_draw_list_draw_indexed_indirect(buffer->driver_id, p_offset, p_draw_count, p_stride);4998} else {4999ERR_FAIL_COND_MSG(p_offset + 16 > buffer->size, "Offset provided (+16) is past the end of buffer.");50005001draw_graph.add_draw_list_draw_indirect(buffer->driver_id, p_offset, p_draw_count, p_stride);5002}50035004draw_list.state.draw_count++;50055006if (buffer->draw_tracker != nullptr) {5007draw_graph.add_draw_list_usage(buffer->draw_tracker, RDG::RESOURCE_USAGE_INDIRECT_BUFFER_READ);5008}50095010_check_transfer_worker_buffer(buffer);5011}50125013void RenderingDevice::draw_list_set_viewport(DrawListID p_list, const Rect2 &p_rect) {5014ERR_FAIL_COND(!draw_list.active);50155016if (p_rect.get_area() == 0) {5017return;5018}50195020draw_list.viewport = p_rect;5021draw_graph.add_draw_list_set_viewport(p_rect);5022}50235024void RenderingDevice::draw_list_enable_scissor(DrawListID p_list, const Rect2 &p_rect) {5025ERR_RENDER_THREAD_GUARD();50265027ERR_FAIL_COND(!draw_list.active);50285029Rect2i rect = p_rect;5030rect.position += draw_list.viewport.position;50315032rect = draw_list.viewport.intersection(rect);50335034if (rect.get_area() == 0) {5035return;5036}50375038draw_graph.add_draw_list_set_scissor(rect);5039}50405041void RenderingDevice::draw_list_disable_scissor(DrawListID p_list) {5042ERR_RENDER_THREAD_GUARD();50435044ERR_FAIL_COND(!draw_list.active);50455046draw_graph.add_draw_list_set_scissor(draw_list.viewport);5047}50485049uint32_t RenderingDevice::draw_list_get_current_pass() {5050ERR_RENDER_THREAD_GUARD_V(0);50515052return draw_list_current_subpass;5053}50545055RenderingDevice::DrawListID RenderingDevice::draw_list_switch_to_next_pass() {5056ERR_RENDER_THREAD_GUARD_V(INVALID_ID);50575058ERR_FAIL_COND_V(!draw_list.active, INVALID_FORMAT_ID);5059ERR_FAIL_COND_V(draw_list_current_subpass >= draw_list_subpass_count - 1, INVALID_FORMAT_ID);50605061draw_list_current_subpass++;50625063Rect2i viewport;5064_draw_list_end(&viewport);50655066draw_graph.add_draw_list_next_subpass(RDD::COMMAND_BUFFER_TYPE_PRIMARY);50675068_draw_list_start(viewport);50695070return int64_t(ID_TYPE_DRAW_LIST) << ID_BASE_SHIFT;5071}50725073#ifndef DISABLE_DEPRECATED5074Error RenderingDevice::draw_list_switch_to_next_pass_split(uint32_t p_splits, DrawListID *r_split_ids) {5075ERR_FAIL_V_MSG(ERR_UNAVAILABLE, "Deprecated. Split draw lists are used automatically by RenderingDevice.");5076}5077#endif50785079void RenderingDevice::_draw_list_start(const Rect2i &p_viewport) {5080draw_list.viewport = p_viewport;5081draw_list.active = true;5082}50835084void RenderingDevice::_draw_list_end(Rect2i *r_last_viewport) {5085if (r_last_viewport) {5086*r_last_viewport = draw_list.viewport;5087}50885089draw_list = DrawList();5090}50915092void RenderingDevice::draw_list_end() {5093ERR_RENDER_THREAD_GUARD();50945095ERR_FAIL_COND_MSG(!draw_list.active, "Immediate draw list is already inactive.");50965097draw_graph.add_draw_list_end();50985099_draw_list_end();51005101for (uint32_t i = 0; i < draw_list_bound_textures.size(); i++) {5102Texture *texture = texture_owner.get_or_null(draw_list_bound_textures[i]);5103ERR_CONTINUE(!texture); // Wtf.5104if (texture->usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) {5105texture->bound = false;5106}5107if (texture->usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {5108texture->bound = false;5109}5110}51115112draw_list_bound_textures.clear();5113}51145115/***********************/5116/**** COMPUTE LISTS ****/5117/***********************/51185119RenderingDevice::ComputeListID RenderingDevice::compute_list_begin() {5120ERR_RENDER_THREAD_GUARD_V(INVALID_ID);51215122ERR_FAIL_COND_V_MSG(compute_list.active, INVALID_ID, "Only one draw/compute list can be active at the same time.");51235124compute_list.active = true;51255126draw_graph.add_compute_list_begin();51275128return ID_TYPE_COMPUTE_LIST;5129}51305131void RenderingDevice::compute_list_bind_compute_pipeline(ComputeListID p_list, RID p_compute_pipeline) {5132ERR_RENDER_THREAD_GUARD();51335134ERR_FAIL_COND(p_list != ID_TYPE_COMPUTE_LIST);5135ERR_FAIL_COND(!compute_list.active);51365137const ComputePipeline *pipeline = compute_pipeline_owner.get_or_null(p_compute_pipeline);5138ERR_FAIL_NULL(pipeline);51395140if (p_compute_pipeline == compute_list.state.pipeline) {5141return; // Redundant state, return.5142}51435144compute_list.state.pipeline = p_compute_pipeline;51455146draw_graph.add_compute_list_bind_pipeline(pipeline->driver_id);51475148if (compute_list.state.pipeline_shader != pipeline->shader) {5149// Shader changed, so descriptor sets may become incompatible.51505151uint32_t pcount = pipeline->set_formats.size(); // Formats count in this pipeline.5152compute_list.state.set_count = MAX(compute_list.state.set_count, pcount);5153const uint32_t *pformats = pipeline->set_formats.ptr(); // Pipeline set formats.51545155uint32_t first_invalid_set = UINT32_MAX; // All valid by default.5156switch (driver->api_trait_get(RDD::API_TRAIT_SHADER_CHANGE_INVALIDATION)) {5157case RDD::SHADER_CHANGE_INVALIDATION_ALL_BOUND_UNIFORM_SETS: {5158first_invalid_set = 0;5159} break;5160case RDD::SHADER_CHANGE_INVALIDATION_INCOMPATIBLE_SETS_PLUS_CASCADE: {5161for (uint32_t i = 0; i < pcount; i++) {5162if (compute_list.state.sets[i].pipeline_expected_format != pformats[i]) {5163first_invalid_set = i;5164break;5165}5166}5167} break;5168case RDD::SHADER_CHANGE_INVALIDATION_ALL_OR_NONE_ACCORDING_TO_LAYOUT_HASH: {5169if (compute_list.state.pipeline_shader_layout_hash != pipeline->shader_layout_hash) {5170first_invalid_set = 0;5171}5172} break;5173}51745175for (uint32_t i = 0; i < pcount; i++) {5176compute_list.state.sets[i].bound = compute_list.state.sets[i].bound && i < first_invalid_set;5177compute_list.state.sets[i].pipeline_expected_format = pformats[i];5178}51795180for (uint32_t i = pcount; i < compute_list.state.set_count; i++) {5181// Unbind the ones above (not used) if exist.5182compute_list.state.sets[i].bound = false;5183}51845185compute_list.state.set_count = pcount; // Update set count.51865187if (pipeline->push_constant_size) {5188#ifdef DEBUG_ENABLED5189compute_list.validation.pipeline_push_constant_supplied = false;5190#endif5191}51925193compute_list.state.pipeline_shader = pipeline->shader;5194compute_list.state.pipeline_shader_driver_id = pipeline->shader_driver_id;5195compute_list.state.pipeline_shader_layout_hash = pipeline->shader_layout_hash;5196compute_list.state.local_group_size[0] = pipeline->local_group_size[0];5197compute_list.state.local_group_size[1] = pipeline->local_group_size[1];5198compute_list.state.local_group_size[2] = pipeline->local_group_size[2];5199}52005201#ifdef DEBUG_ENABLED5202// Update compute pass pipeline info.5203compute_list.validation.pipeline_active = true;5204compute_list.validation.pipeline_push_constant_size = pipeline->push_constant_size;5205#endif5206}52075208void RenderingDevice::compute_list_bind_uniform_set(ComputeListID p_list, RID p_uniform_set, uint32_t p_index) {5209ERR_RENDER_THREAD_GUARD();52105211ERR_FAIL_COND(p_list != ID_TYPE_COMPUTE_LIST);5212ERR_FAIL_COND(!compute_list.active);52135214#ifdef DEBUG_ENABLED5215ERR_FAIL_COND_MSG(p_index >= driver->limit_get(LIMIT_MAX_BOUND_UNIFORM_SETS) || p_index >= MAX_UNIFORM_SETS,5216"Attempting to bind a descriptor set (" + itos(p_index) + ") greater than what the hardware supports (" + itos(driver->limit_get(LIMIT_MAX_BOUND_UNIFORM_SETS)) + ").");5217#endif52185219UniformSet *uniform_set = uniform_set_owner.get_or_null(p_uniform_set);5220ERR_FAIL_NULL(uniform_set);52215222if (p_index > compute_list.state.set_count) {5223compute_list.state.set_count = p_index;5224}52255226compute_list.state.sets[p_index].uniform_set_driver_id = uniform_set->driver_id; // Update set pointer.5227compute_list.state.sets[p_index].bound = false; // Needs rebind.5228compute_list.state.sets[p_index].uniform_set_format = uniform_set->format;5229compute_list.state.sets[p_index].uniform_set = p_uniform_set;52305231#if 05232{ // Validate that textures bound are not attached as framebuffer bindings.5233uint32_t attachable_count = uniform_set->attachable_textures.size();5234const RID *attachable_ptr = uniform_set->attachable_textures.ptr();5235uint32_t bound_count = draw_list_bound_textures.size();5236const RID *bound_ptr = draw_list_bound_textures.ptr();5237for (uint32_t i = 0; i < attachable_count; i++) {5238for (uint32_t j = 0; j < bound_count; j++) {5239ERR_FAIL_COND_MSG(attachable_ptr[i] == bound_ptr[j],5240"Attempted to use the same texture in framebuffer attachment and a uniform set, this is not allowed.");5241}5242}5243}5244#endif5245}52465247void RenderingDevice::compute_list_set_push_constant(ComputeListID p_list, const void *p_data, uint32_t p_data_size) {5248ERR_RENDER_THREAD_GUARD();52495250ERR_FAIL_COND(p_list != ID_TYPE_COMPUTE_LIST);5251ERR_FAIL_COND(!compute_list.active);5252ERR_FAIL_COND_MSG(p_data_size > MAX_PUSH_CONSTANT_SIZE, "Push constants can't be bigger than 128 bytes to maintain compatibility.");52535254#ifdef DEBUG_ENABLED5255ERR_FAIL_COND_MSG(p_data_size != compute_list.validation.pipeline_push_constant_size,5256"This compute pipeline requires (" + itos(compute_list.validation.pipeline_push_constant_size) + ") bytes of push constant data, supplied: (" + itos(p_data_size) + ")");5257#endif52585259draw_graph.add_compute_list_set_push_constant(compute_list.state.pipeline_shader_driver_id, p_data, p_data_size);52605261// Store it in the state in case we need to restart the compute list.5262memcpy(compute_list.state.push_constant_data, p_data, p_data_size);5263compute_list.state.push_constant_size = p_data_size;52645265#ifdef DEBUG_ENABLED5266compute_list.validation.pipeline_push_constant_supplied = true;5267#endif5268}52695270void RenderingDevice::compute_list_dispatch(ComputeListID p_list, uint32_t p_x_groups, uint32_t p_y_groups, uint32_t p_z_groups) {5271ERR_RENDER_THREAD_GUARD();52725273ERR_FAIL_COND(p_list != ID_TYPE_COMPUTE_LIST);5274ERR_FAIL_COND(!compute_list.active);52755276#ifdef DEBUG_ENABLED5277ERR_FAIL_COND_MSG(p_x_groups == 0, "Dispatch amount of X compute groups (" + itos(p_x_groups) + ") is zero.");5278ERR_FAIL_COND_MSG(p_z_groups == 0, "Dispatch amount of Z compute groups (" + itos(p_z_groups) + ") is zero.");5279ERR_FAIL_COND_MSG(p_y_groups == 0, "Dispatch amount of Y compute groups (" + itos(p_y_groups) + ") is zero.");5280ERR_FAIL_COND_MSG(p_x_groups > driver->limit_get(LIMIT_MAX_COMPUTE_WORKGROUP_COUNT_X),5281"Dispatch amount of X compute groups (" + itos(p_x_groups) + ") is larger than device limit (" + itos(driver->limit_get(LIMIT_MAX_COMPUTE_WORKGROUP_COUNT_X)) + ")");5282ERR_FAIL_COND_MSG(p_y_groups > driver->limit_get(LIMIT_MAX_COMPUTE_WORKGROUP_COUNT_Y),5283"Dispatch amount of Y compute groups (" + itos(p_y_groups) + ") is larger than device limit (" + itos(driver->limit_get(LIMIT_MAX_COMPUTE_WORKGROUP_COUNT_Y)) + ")");5284ERR_FAIL_COND_MSG(p_z_groups > driver->limit_get(LIMIT_MAX_COMPUTE_WORKGROUP_COUNT_Z),5285"Dispatch amount of Z compute groups (" + itos(p_z_groups) + ") is larger than device limit (" + itos(driver->limit_get(LIMIT_MAX_COMPUTE_WORKGROUP_COUNT_Z)) + ")");5286#endif52875288#ifdef DEBUG_ENABLED52895290ERR_FAIL_COND_MSG(!compute_list.validation.pipeline_active, "No compute pipeline was set before attempting to draw.");52915292if (compute_list.validation.pipeline_push_constant_size > 0) {5293// Using push constants, check that they were supplied.5294ERR_FAIL_COND_MSG(!compute_list.validation.pipeline_push_constant_supplied,5295"The shader in this pipeline requires a push constant to be set before drawing, but it's not present.");5296}52975298#endif52995300#ifdef DEBUG_ENABLED5301for (uint32_t i = 0; i < compute_list.state.set_count; i++) {5302if (compute_list.state.sets[i].pipeline_expected_format == 0) {5303// Nothing expected by this pipeline.5304continue;5305}53065307if (compute_list.state.sets[i].pipeline_expected_format != compute_list.state.sets[i].uniform_set_format) {5308if (compute_list.state.sets[i].uniform_set_format == 0) {5309ERR_FAIL_MSG("Uniforms were never supplied for set (" + itos(i) + ") at the time of drawing, which are required by the pipeline.");5310} else if (uniform_set_owner.owns(compute_list.state.sets[i].uniform_set)) {5311UniformSet *us = uniform_set_owner.get_or_null(compute_list.state.sets[i].uniform_set);5312ERR_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(compute_list.state.pipeline_shader));5313} else {5314ERR_FAIL_MSG("Uniforms supplied for set (" + itos(i) + ", which was just freed) are not the same format as required by the pipeline shader. Pipeline shader requires the following bindings:\n" + _shader_uniform_debug(compute_list.state.pipeline_shader));5315}5316}5317}5318#endif5319thread_local LocalVector<RDD::UniformSetID> valid_descriptor_ids;5320valid_descriptor_ids.clear();5321valid_descriptor_ids.resize(compute_list.state.set_count);53225323uint32_t valid_set_count = 0;5324uint32_t first_set_index = 0;5325uint32_t last_set_index = 0;5326bool found_first_set = false;53275328for (uint32_t i = 0; i < compute_list.state.set_count; i++) {5329if (compute_list.state.sets[i].pipeline_expected_format == 0) {5330// Nothing expected by this pipeline.5331continue;5332}53335334if (!compute_list.state.sets[i].bound && !found_first_set) {5335first_set_index = i;5336found_first_set = true;5337}5338// Prepare descriptor sets if the API doesn't use pipeline barriers.5339if (!driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) {5340draw_graph.add_compute_list_uniform_set_prepare_for_use(compute_list.state.pipeline_shader_driver_id, compute_list.state.sets[i].uniform_set_driver_id, i);5341}5342}53435344// Bind descriptor sets.5345for (uint32_t i = first_set_index; i < compute_list.state.set_count; i++) {5346if (compute_list.state.sets[i].pipeline_expected_format == 0) {5347continue; // Nothing expected by this pipeline.5348}53495350if (!compute_list.state.sets[i].bound) {5351// Descriptor set batching5352if (descriptor_set_batching) {5353// All good, see if this requires re-binding.5354if (i - last_set_index > 1) {5355// If the descriptor sets are not contiguous, bind the previous ones and start a new batch.5356draw_graph.add_compute_list_bind_uniform_sets(compute_list.state.pipeline_shader_driver_id, valid_descriptor_ids, first_set_index, valid_set_count);53575358first_set_index = i;5359valid_set_count = 1;5360valid_descriptor_ids[0] = compute_list.state.sets[i].uniform_set_driver_id;5361} else {5362// Otherwise, keep storing in the current batch.5363valid_descriptor_ids[valid_set_count] = compute_list.state.sets[i].uniform_set_driver_id;5364valid_set_count++;5365}53665367last_set_index = i;5368} else {5369draw_graph.add_compute_list_bind_uniform_set(compute_list.state.pipeline_shader_driver_id, compute_list.state.sets[i].uniform_set_driver_id, i);5370}5371UniformSet *uniform_set = uniform_set_owner.get_or_null(compute_list.state.sets[i].uniform_set);5372_uniform_set_update_shared(uniform_set);53735374draw_graph.add_compute_list_usages(uniform_set->draw_trackers, uniform_set->draw_trackers_usage);5375compute_list.state.sets[i].bound = true;5376}5377}53785379// Bind the remaining batch.5380if (valid_set_count > 0) {5381draw_graph.add_compute_list_bind_uniform_sets(compute_list.state.pipeline_shader_driver_id, valid_descriptor_ids, first_set_index, valid_set_count);5382}5383draw_graph.add_compute_list_dispatch(p_x_groups, p_y_groups, p_z_groups);5384compute_list.state.dispatch_count++;5385}53865387void RenderingDevice::compute_list_dispatch_threads(ComputeListID p_list, uint32_t p_x_threads, uint32_t p_y_threads, uint32_t p_z_threads) {5388ERR_RENDER_THREAD_GUARD();53895390ERR_FAIL_COND(p_list != ID_TYPE_COMPUTE_LIST);5391ERR_FAIL_COND(!compute_list.active);53925393#ifdef DEBUG_ENABLED5394ERR_FAIL_COND_MSG(p_x_threads == 0, "Dispatch amount of X compute threads (" + itos(p_x_threads) + ") is zero.");5395ERR_FAIL_COND_MSG(p_y_threads == 0, "Dispatch amount of Y compute threads (" + itos(p_y_threads) + ") is zero.");5396ERR_FAIL_COND_MSG(p_z_threads == 0, "Dispatch amount of Z compute threads (" + itos(p_z_threads) + ") is zero.");5397#endif53985399#ifdef DEBUG_ENABLED54005401ERR_FAIL_COND_MSG(!compute_list.validation.pipeline_active, "No compute pipeline was set before attempting to draw.");54025403if (compute_list.validation.pipeline_push_constant_size > 0) {5404// Using push constants, check that they were supplied.5405ERR_FAIL_COND_MSG(!compute_list.validation.pipeline_push_constant_supplied,5406"The shader in this pipeline requires a push constant to be set before drawing, but it's not present.");5407}54085409#endif54105411compute_list_dispatch(p_list, Math::division_round_up(p_x_threads, compute_list.state.local_group_size[0]), Math::division_round_up(p_y_threads, compute_list.state.local_group_size[1]), Math::division_round_up(p_z_threads, compute_list.state.local_group_size[2]));5412}54135414void RenderingDevice::compute_list_dispatch_indirect(ComputeListID p_list, RID p_buffer, uint32_t p_offset) {5415ERR_RENDER_THREAD_GUARD();54165417ERR_FAIL_COND(p_list != ID_TYPE_COMPUTE_LIST);5418ERR_FAIL_COND(!compute_list.active);54195420Buffer *buffer = storage_buffer_owner.get_or_null(p_buffer);5421ERR_FAIL_NULL(buffer);54225423ERR_FAIL_COND_MSG(!buffer->usage.has_flag(RDD::BUFFER_USAGE_INDIRECT_BIT), "Buffer provided was not created to do indirect dispatch.");54245425ERR_FAIL_COND_MSG(p_offset + 12 > buffer->size, "Offset provided (+12) is past the end of buffer.");54265427#ifdef DEBUG_ENABLED54285429ERR_FAIL_COND_MSG(!compute_list.validation.pipeline_active, "No compute pipeline was set before attempting to draw.");54305431if (compute_list.validation.pipeline_push_constant_size > 0) {5432// Using push constants, check that they were supplied.5433ERR_FAIL_COND_MSG(!compute_list.validation.pipeline_push_constant_supplied,5434"The shader in this pipeline requires a push constant to be set before drawing, but it's not present.");5435}54365437#endif54385439#ifdef DEBUG_ENABLED5440for (uint32_t i = 0; i < compute_list.state.set_count; i++) {5441if (compute_list.state.sets[i].pipeline_expected_format == 0) {5442// Nothing expected by this pipeline.5443continue;5444}54455446if (compute_list.state.sets[i].pipeline_expected_format != compute_list.state.sets[i].uniform_set_format) {5447if (compute_list.state.sets[i].uniform_set_format == 0) {5448ERR_FAIL_MSG("Uniforms were never supplied for set (" + itos(i) + ") at the time of drawing, which are required by the pipeline.");5449} else if (uniform_set_owner.owns(compute_list.state.sets[i].uniform_set)) {5450UniformSet *us = uniform_set_owner.get_or_null(compute_list.state.sets[i].uniform_set);5451ERR_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(compute_list.state.pipeline_shader));5452} else {5453ERR_FAIL_MSG("Uniforms supplied for set (" + itos(i) + ", which was just freed) are not the same format as required by the pipeline shader. Pipeline shader requires the following bindings:\n" + _shader_uniform_debug(compute_list.state.pipeline_shader));5454}5455}5456}5457#endif5458thread_local LocalVector<RDD::UniformSetID> valid_descriptor_ids;5459valid_descriptor_ids.clear();5460valid_descriptor_ids.resize(compute_list.state.set_count);54615462uint32_t valid_set_count = 0;5463uint32_t first_set_index = 0;5464uint32_t last_set_index = 0;5465bool found_first_set = false;54665467for (uint32_t i = 0; i < compute_list.state.set_count; i++) {5468if (compute_list.state.sets[i].pipeline_expected_format == 0) {5469// Nothing expected by this pipeline.5470continue;5471}54725473if (!compute_list.state.sets[i].bound && !found_first_set) {5474first_set_index = i;5475found_first_set = true;5476}54775478// Prepare descriptor sets if the API doesn't use pipeline barriers.5479if (!driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) {5480draw_graph.add_compute_list_uniform_set_prepare_for_use(compute_list.state.pipeline_shader_driver_id, compute_list.state.sets[i].uniform_set_driver_id, i);5481}5482}54835484// Bind descriptor sets.5485for (uint32_t i = first_set_index; i < compute_list.state.set_count; i++) {5486if (compute_list.state.sets[i].pipeline_expected_format == 0) {5487continue; // Nothing expected by this pipeline.5488}54895490if (!compute_list.state.sets[i].bound) {5491// All good, see if this requires re-binding.5492if (i - last_set_index > 1) {5493// If the descriptor sets are not contiguous, bind the previous ones and start a new batch.5494draw_graph.add_compute_list_bind_uniform_sets(compute_list.state.pipeline_shader_driver_id, valid_descriptor_ids, first_set_index, valid_set_count);54955496first_set_index = i;5497valid_set_count = 1;5498valid_descriptor_ids[0] = compute_list.state.sets[i].uniform_set_driver_id;5499} else {5500// Otherwise, keep storing in the current batch.5501valid_descriptor_ids[valid_set_count] = compute_list.state.sets[i].uniform_set_driver_id;5502valid_set_count++;5503}55045505last_set_index = i;55065507UniformSet *uniform_set = uniform_set_owner.get_or_null(compute_list.state.sets[i].uniform_set);5508_uniform_set_update_shared(uniform_set);55095510draw_graph.add_compute_list_usages(uniform_set->draw_trackers, uniform_set->draw_trackers_usage);5511compute_list.state.sets[i].bound = true;5512}5513}55145515// Bind the remaining batch.5516if (valid_set_count > 0) {5517draw_graph.add_compute_list_bind_uniform_sets(compute_list.state.pipeline_shader_driver_id, valid_descriptor_ids, first_set_index, valid_set_count);5518}55195520draw_graph.add_compute_list_dispatch_indirect(buffer->driver_id, p_offset);5521compute_list.state.dispatch_count++;55225523if (buffer->draw_tracker != nullptr) {5524draw_graph.add_compute_list_usage(buffer->draw_tracker, RDG::RESOURCE_USAGE_INDIRECT_BUFFER_READ);5525}55265527_check_transfer_worker_buffer(buffer);5528}55295530void RenderingDevice::compute_list_add_barrier(ComputeListID p_list) {5531ERR_RENDER_THREAD_GUARD();55325533compute_list_barrier_state = compute_list.state;5534compute_list_end();5535compute_list_begin();55365537if (compute_list_barrier_state.pipeline.is_valid()) {5538compute_list_bind_compute_pipeline(p_list, compute_list_barrier_state.pipeline);5539}55405541for (uint32_t i = 0; i < compute_list_barrier_state.set_count; i++) {5542if (compute_list_barrier_state.sets[i].uniform_set.is_valid()) {5543compute_list_bind_uniform_set(p_list, compute_list_barrier_state.sets[i].uniform_set, i);5544}5545}55465547if (compute_list_barrier_state.push_constant_size > 0) {5548compute_list_set_push_constant(p_list, compute_list_barrier_state.push_constant_data, compute_list_barrier_state.push_constant_size);5549}5550}55515552void RenderingDevice::compute_list_end() {5553ERR_RENDER_THREAD_GUARD();55545555ERR_FAIL_COND(!compute_list.active);55565557draw_graph.add_compute_list_end();55585559compute_list = ComputeList();5560}55615562#ifndef DISABLE_DEPRECATED5563void RenderingDevice::barrier(BitField<BarrierMask> p_from, BitField<BarrierMask> p_to) {5564WARN_PRINT("Deprecated. Barriers are automatically inserted by RenderingDevice.");5565}55665567void RenderingDevice::full_barrier() {5568WARN_PRINT("Deprecated. Barriers are automatically inserted by RenderingDevice.");5569}5570#endif55715572/*************************/5573/**** TRANSFER WORKER ****/5574/*************************/55755576static uint32_t _get_alignment_offset(uint32_t p_offset, uint32_t p_required_align) {5577uint32_t alignment_offset = (p_required_align > 0) ? (p_offset % p_required_align) : 0;5578if (alignment_offset != 0) {5579// If a particular alignment is required, add the offset as part of the required size.5580alignment_offset = p_required_align - alignment_offset;5581}55825583return alignment_offset;5584}55855586RenderingDevice::TransferWorker *RenderingDevice::_acquire_transfer_worker(uint32_t p_transfer_size, uint32_t p_required_align, uint32_t &r_staging_offset) {5587// Find the first worker that is not currently executing anything and has enough size for the transfer.5588// If no workers are available, we make a new one. If we're not allowed to make new ones, we wait until one of them is available.5589TransferWorker *transfer_worker = nullptr;5590uint32_t available_list_index = 0;5591bool transfer_worker_busy = true;5592bool transfer_worker_full = true;5593{5594MutexLock pool_lock(transfer_worker_pool_mutex);55955596// If no workers are available and we've reached the max pool capacity, wait until one of them becomes available.5597bool transfer_worker_pool_full = transfer_worker_pool.size() >= transfer_worker_pool_max_size;5598while (transfer_worker_pool_available_list.is_empty() && transfer_worker_pool_full) {5599transfer_worker_pool_condition.wait(pool_lock);5600}56015602// Look at all available workers first.5603for (uint32_t i = 0; i < transfer_worker_pool_available_list.size(); i++) {5604uint32_t worker_index = transfer_worker_pool_available_list[i];5605TransferWorker *candidate_worker = transfer_worker_pool[worker_index];5606candidate_worker->thread_mutex.lock();56075608// Figure out if the worker can fit the transfer.5609uint32_t alignment_offset = _get_alignment_offset(candidate_worker->staging_buffer_size_in_use, p_required_align);5610uint32_t required_size = candidate_worker->staging_buffer_size_in_use + p_transfer_size + alignment_offset;5611bool candidate_worker_busy = candidate_worker->submitted;5612bool candidate_worker_full = required_size > candidate_worker->staging_buffer_size_allocated;5613bool pick_candidate = false;5614if (!candidate_worker_busy && !candidate_worker_full) {5615// A worker that can fit the transfer and is not waiting for a previous execution is the best possible candidate.5616pick_candidate = true;5617} else if (!candidate_worker_busy) {5618// The worker can't fit the transfer but it's not currently doing anything.5619// We pick it as a possible candidate if the current one is busy.5620pick_candidate = transfer_worker_busy;5621} else if (!candidate_worker_full) {5622// The worker can fit the transfer but it's currently executing previous work.5623// We pick it as a possible candidate if the current one is both busy and full.5624pick_candidate = transfer_worker_busy && transfer_worker_full;5625} else if (transfer_worker == nullptr) {5626// The worker can't fit the transfer and it's currently executing work, so it's the worst candidate.5627// We only pick if no candidate has been picked yet.5628pick_candidate = true;5629}56305631if (pick_candidate) {5632if (transfer_worker != nullptr) {5633// Release the lock for the worker that was picked previously.5634transfer_worker->thread_mutex.unlock();5635}56365637// Keep the lock active for this worker.5638transfer_worker = candidate_worker;5639transfer_worker_busy = candidate_worker_busy;5640transfer_worker_full = candidate_worker_full;5641available_list_index = i;56425643if (!transfer_worker_busy && !transfer_worker_full) {5644// Best possible candidate, stop searching early.5645break;5646}5647} else {5648// Release the lock for the candidate.5649candidate_worker->thread_mutex.unlock();5650}5651}56525653if (transfer_worker != nullptr) {5654// A worker was picked, remove it from the available list.5655transfer_worker_pool_available_list.remove_at(available_list_index);5656} else {5657DEV_ASSERT(!transfer_worker_pool_full && "A transfer worker should never be created when the pool is full.");56585659// No existing worker was picked, we create a new one.5660transfer_worker = memnew(TransferWorker);5661transfer_worker->command_fence = driver->fence_create();5662transfer_worker->command_pool = driver->command_pool_create(transfer_queue_family, RDD::COMMAND_BUFFER_TYPE_PRIMARY);5663transfer_worker->command_buffer = driver->command_buffer_create(transfer_worker->command_pool);5664transfer_worker->index = transfer_worker_pool.size();5665transfer_worker_pool.push_back(transfer_worker);5666transfer_worker_operation_used_by_draw.push_back(0);5667transfer_worker->thread_mutex.lock();5668}5669}56705671if (transfer_worker->submitted) {5672// Wait for the worker if the command buffer was submitted but it hasn't finished processing yet.5673_wait_for_transfer_worker(transfer_worker);5674}56755676uint32_t alignment_offset = _get_alignment_offset(transfer_worker->staging_buffer_size_in_use, p_required_align);5677transfer_worker->max_transfer_size = MAX(transfer_worker->max_transfer_size, p_transfer_size);56785679uint32_t required_size = transfer_worker->staging_buffer_size_in_use + p_transfer_size + alignment_offset;5680if (required_size > transfer_worker->staging_buffer_size_allocated) {5681// If there's not enough bytes to use on the staging buffer, we submit everything pending from the worker and wait for the work to be finished.5682if (transfer_worker->recording) {5683_end_transfer_worker(transfer_worker);5684_submit_transfer_worker(transfer_worker);5685}56865687if (transfer_worker->submitted) {5688_wait_for_transfer_worker(transfer_worker);5689}56905691alignment_offset = 0;56925693// If the staging buffer can't fit the transfer, we recreate the buffer.5694const uint32_t expected_buffer_size_minimum = 16 * 1024;5695uint32_t expected_buffer_size = MAX(transfer_worker->max_transfer_size, expected_buffer_size_minimum);5696if (expected_buffer_size > transfer_worker->staging_buffer_size_allocated) {5697if (transfer_worker->staging_buffer.id != 0) {5698driver->buffer_free(transfer_worker->staging_buffer);5699}57005701uint32_t new_staging_buffer_size = next_power_of_2(expected_buffer_size);5702transfer_worker->staging_buffer_size_allocated = new_staging_buffer_size;5703transfer_worker->staging_buffer = driver->buffer_create(new_staging_buffer_size, RDD::BUFFER_USAGE_TRANSFER_FROM_BIT, RDD::MEMORY_ALLOCATION_TYPE_CPU);5704}5705}57065707// Add the alignment before storing the offset that will be returned.5708transfer_worker->staging_buffer_size_in_use += alignment_offset;57095710// Store the offset to return and increment the current size.5711r_staging_offset = transfer_worker->staging_buffer_size_in_use;5712transfer_worker->staging_buffer_size_in_use += p_transfer_size;57135714if (!transfer_worker->recording) {5715// Begin the command buffer if the worker wasn't recording yet.5716driver->command_buffer_begin(transfer_worker->command_buffer);5717transfer_worker->recording = true;5718}57195720return transfer_worker;5721}57225723void RenderingDevice::_release_transfer_worker(TransferWorker *p_transfer_worker) {5724p_transfer_worker->thread_mutex.unlock();57255726transfer_worker_pool_mutex.lock();5727transfer_worker_pool_available_list.push_back(p_transfer_worker->index);5728transfer_worker_pool_mutex.unlock();5729transfer_worker_pool_condition.notify_one();5730}57315732void RenderingDevice::_end_transfer_worker(TransferWorker *p_transfer_worker) {5733driver->command_buffer_end(p_transfer_worker->command_buffer);5734p_transfer_worker->recording = false;5735}57365737void RenderingDevice::_submit_transfer_worker(TransferWorker *p_transfer_worker, VectorView<RDD::SemaphoreID> p_signal_semaphores) {5738driver->command_queue_execute_and_present(transfer_queue, {}, p_transfer_worker->command_buffer, p_signal_semaphores, p_transfer_worker->command_fence, {});57395740for (uint32_t i = 0; i < p_signal_semaphores.size(); i++) {5741// Indicate the frame should wait on these semaphores before executing the main command buffer.5742frames[frame].semaphores_to_wait_on.push_back(p_signal_semaphores[i]);5743}57445745p_transfer_worker->submitted = true;57465747{5748MutexLock lock(p_transfer_worker->operations_mutex);5749p_transfer_worker->operations_submitted = p_transfer_worker->operations_counter;5750}5751}57525753void RenderingDevice::_wait_for_transfer_worker(TransferWorker *p_transfer_worker) {5754driver->fence_wait(p_transfer_worker->command_fence);5755driver->command_pool_reset(p_transfer_worker->command_pool);5756p_transfer_worker->staging_buffer_size_in_use = 0;5757p_transfer_worker->submitted = false;57585759{5760MutexLock lock(p_transfer_worker->operations_mutex);5761p_transfer_worker->operations_processed = p_transfer_worker->operations_submitted;5762}57635764_flush_barriers_for_transfer_worker(p_transfer_worker);5765}57665767void RenderingDevice::_flush_barriers_for_transfer_worker(TransferWorker *p_transfer_worker) {5768// Caller must have already acquired the mutex for the worker.5769if (!p_transfer_worker->texture_barriers.is_empty()) {5770MutexLock transfer_worker_lock(transfer_worker_pool_texture_barriers_mutex);5771for (uint32_t i = 0; i < p_transfer_worker->texture_barriers.size(); i++) {5772transfer_worker_pool_texture_barriers.push_back(p_transfer_worker->texture_barriers[i]);5773}57745775p_transfer_worker->texture_barriers.clear();5776}5777}57785779void RenderingDevice::_check_transfer_worker_operation(uint32_t p_transfer_worker_index, uint64_t p_transfer_worker_operation) {5780TransferWorker *transfer_worker = transfer_worker_pool[p_transfer_worker_index];5781MutexLock lock(transfer_worker->operations_mutex);5782uint64_t &dst_operation = transfer_worker_operation_used_by_draw[transfer_worker->index];5783dst_operation = MAX(dst_operation, p_transfer_worker_operation);5784}57855786void RenderingDevice::_check_transfer_worker_buffer(Buffer *p_buffer) {5787if (p_buffer->transfer_worker_index >= 0) {5788_check_transfer_worker_operation(p_buffer->transfer_worker_index, p_buffer->transfer_worker_operation);5789p_buffer->transfer_worker_index = -1;5790}5791}57925793void RenderingDevice::_check_transfer_worker_texture(Texture *p_texture) {5794if (p_texture->transfer_worker_index >= 0) {5795_check_transfer_worker_operation(p_texture->transfer_worker_index, p_texture->transfer_worker_operation);5796p_texture->transfer_worker_index = -1;5797}5798}57995800void RenderingDevice::_check_transfer_worker_vertex_array(VertexArray *p_vertex_array) {5801if (!p_vertex_array->transfer_worker_indices.is_empty()) {5802for (int i = 0; i < p_vertex_array->transfer_worker_indices.size(); i++) {5803_check_transfer_worker_operation(p_vertex_array->transfer_worker_indices[i], p_vertex_array->transfer_worker_operations[i]);5804}58055806p_vertex_array->transfer_worker_indices.clear();5807p_vertex_array->transfer_worker_operations.clear();5808}5809}58105811void RenderingDevice::_check_transfer_worker_index_array(IndexArray *p_index_array) {5812if (p_index_array->transfer_worker_index >= 0) {5813_check_transfer_worker_operation(p_index_array->transfer_worker_index, p_index_array->transfer_worker_operation);5814p_index_array->transfer_worker_index = -1;5815}5816}58175818void RenderingDevice::_submit_transfer_workers(RDD::CommandBufferID p_draw_command_buffer) {5819MutexLock transfer_worker_lock(transfer_worker_pool_mutex);5820for (uint32_t i = 0; i < transfer_worker_pool.size(); i++) {5821TransferWorker *worker = transfer_worker_pool[i];5822if (p_draw_command_buffer) {5823MutexLock lock(worker->operations_mutex);5824if (worker->operations_processed >= transfer_worker_operation_used_by_draw[worker->index]) {5825// The operation used by the draw has already been processed, we don't need to wait on the worker.5826continue;5827}5828}58295830{5831MutexLock lock(worker->thread_mutex);5832if (worker->recording) {5833VectorView<RDD::SemaphoreID> semaphores = p_draw_command_buffer ? frames[frame].transfer_worker_semaphores[i] : VectorView<RDD::SemaphoreID>();5834_end_transfer_worker(worker);5835_submit_transfer_worker(worker, semaphores);5836}58375838if (p_draw_command_buffer) {5839_flush_barriers_for_transfer_worker(worker);5840}5841}5842}5843}58445845void RenderingDevice::_submit_transfer_barriers(RDD::CommandBufferID p_draw_command_buffer) {5846MutexLock transfer_worker_lock(transfer_worker_pool_texture_barriers_mutex);5847if (!transfer_worker_pool_texture_barriers.is_empty()) {5848driver->command_pipeline_barrier(p_draw_command_buffer, RDD::PIPELINE_STAGE_COPY_BIT, RDD::PIPELINE_STAGE_ALL_COMMANDS_BIT, {}, {}, transfer_worker_pool_texture_barriers);5849transfer_worker_pool_texture_barriers.clear();5850}5851}58525853void RenderingDevice::_wait_for_transfer_workers() {5854MutexLock transfer_worker_lock(transfer_worker_pool_mutex);5855for (TransferWorker *worker : transfer_worker_pool) {5856MutexLock lock(worker->thread_mutex);5857if (worker->submitted) {5858_wait_for_transfer_worker(worker);5859}5860}5861}58625863void RenderingDevice::_free_transfer_workers() {5864MutexLock transfer_worker_lock(transfer_worker_pool_mutex);5865for (TransferWorker *worker : transfer_worker_pool) {5866driver->fence_free(worker->command_fence);5867driver->buffer_free(worker->staging_buffer);5868driver->command_pool_free(worker->command_pool);5869memdelete(worker);5870}58715872transfer_worker_pool.clear();5873}58745875/***********************/5876/**** COMMAND GRAPH ****/5877/***********************/58785879bool RenderingDevice::_texture_make_mutable(Texture *p_texture, RID p_texture_id) {5880if (p_texture->draw_tracker != nullptr) {5881// Texture already has a tracker.5882return false;5883} else {5884if (p_texture->owner.is_valid()) {5885// Texture has an owner.5886Texture *owner_texture = texture_owner.get_or_null(p_texture->owner);5887ERR_FAIL_NULL_V(owner_texture, false);58885889if (owner_texture->draw_tracker != nullptr) {5890// Create a tracker for this dependency in particular.5891if (p_texture->slice_type == TEXTURE_SLICE_MAX) {5892// Shared texture.5893p_texture->draw_tracker = owner_texture->draw_tracker;5894p_texture->draw_tracker->reference_count++;5895} else {5896// Slice texture.5897if (owner_texture->slice_trackers == nullptr) {5898owner_texture->slice_trackers = memnew((HashMap<Rect2i, RDG::ResourceTracker *>));5899}5900HashMap<Rect2i, RDG::ResourceTracker *>::ConstIterator draw_tracker_iterator = owner_texture->slice_trackers->find(p_texture->slice_rect);5901RDG::ResourceTracker *draw_tracker = nullptr;5902if (draw_tracker_iterator != owner_texture->slice_trackers->end()) {5903// Reuse the tracker at the matching rectangle.5904draw_tracker = draw_tracker_iterator->value;5905} else {5906// Create a new tracker and store it on the map.5907draw_tracker = RDG::resource_tracker_create();5908draw_tracker->parent = owner_texture->draw_tracker;5909draw_tracker->texture_driver_id = p_texture->driver_id;5910draw_tracker->texture_size = Size2i(p_texture->width, p_texture->height);5911draw_tracker->texture_subresources = p_texture->barrier_range();5912draw_tracker->texture_usage = p_texture->usage_flags;5913draw_tracker->texture_slice_or_dirty_rect = p_texture->slice_rect;5914(*owner_texture->slice_trackers)[p_texture->slice_rect] = draw_tracker;5915}59165917p_texture->draw_tracker = draw_tracker;5918p_texture->draw_tracker->reference_count++;5919}59205921if (p_texture_id.is_valid()) {5922_dependencies_make_mutable(p_texture_id, p_texture->draw_tracker);5923}5924} else {5925// Delegate this to the owner instead, as it'll make all its dependencies mutable.5926_texture_make_mutable(owner_texture, p_texture->owner);5927}5928} else {5929// Regular texture.5930p_texture->draw_tracker = RDG::resource_tracker_create();5931p_texture->draw_tracker->texture_driver_id = p_texture->driver_id;5932p_texture->draw_tracker->texture_size = Size2i(p_texture->width, p_texture->height);5933p_texture->draw_tracker->texture_subresources = p_texture->barrier_range();5934p_texture->draw_tracker->texture_usage = p_texture->usage_flags;5935p_texture->draw_tracker->is_discardable = p_texture->is_discardable;5936p_texture->draw_tracker->reference_count = 1;59375938if (p_texture_id.is_valid()) {5939if (p_texture->has_initial_data) {5940// If the texture was initialized with initial data but wasn't made mutable from the start, assume the texture sampling usage.5941p_texture->draw_tracker->usage = RDG::RESOURCE_USAGE_TEXTURE_SAMPLE;5942}59435944_dependencies_make_mutable(p_texture_id, p_texture->draw_tracker);5945}5946}59475948return true;5949}5950}59515952bool RenderingDevice::_buffer_make_mutable(Buffer *p_buffer, RID p_buffer_id) {5953if (p_buffer->draw_tracker != nullptr) {5954// Buffer already has a tracker.5955return false;5956} else {5957// Create a tracker for the buffer and make all its dependencies mutable.5958p_buffer->draw_tracker = RDG::resource_tracker_create();5959p_buffer->draw_tracker->buffer_driver_id = p_buffer->driver_id;5960if (p_buffer_id.is_valid()) {5961_dependencies_make_mutable(p_buffer_id, p_buffer->draw_tracker);5962}59635964return true;5965}5966}59675968bool RenderingDevice::_vertex_array_make_mutable(VertexArray *p_vertex_array, RID p_resource_id, RDG::ResourceTracker *p_resource_tracker) {5969if (!p_vertex_array->untracked_buffers.has(p_resource_id)) {5970// Vertex array thinks the buffer is already tracked or does not use it.5971return false;5972} else {5973// Vertex array is aware of the buffer but it isn't being tracked.5974p_vertex_array->draw_trackers.push_back(p_resource_tracker);5975p_vertex_array->untracked_buffers.erase(p_resource_id);5976return true;5977}5978}59795980bool RenderingDevice::_index_array_make_mutable(IndexArray *p_index_array, RDG::ResourceTracker *p_resource_tracker) {5981if (p_index_array->draw_tracker != nullptr) {5982// Index array already has a tracker.5983return false;5984} else {5985// Index array should assign the tracker from the buffer.5986p_index_array->draw_tracker = p_resource_tracker;5987return true;5988}5989}59905991bool RenderingDevice::_uniform_set_make_mutable(UniformSet *p_uniform_set, RID p_resource_id, RDG::ResourceTracker *p_resource_tracker) {5992HashMap<RID, RDG::ResourceUsage>::Iterator E = p_uniform_set->untracked_usage.find(p_resource_id);5993if (!E) {5994// Uniform set thinks the resource is already tracked or does not use it.5995return false;5996} else {5997// Uniform set has seen the resource but hasn't added its tracker yet.5998p_uniform_set->draw_trackers.push_back(p_resource_tracker);5999p_uniform_set->draw_trackers_usage.push_back(E->value);6000p_uniform_set->untracked_usage.remove(E);6001return true;6002}6003}60046005bool RenderingDevice::_dependency_make_mutable(RID p_id, RID p_resource_id, RDG::ResourceTracker *p_resource_tracker) {6006if (texture_owner.owns(p_id)) {6007Texture *texture = texture_owner.get_or_null(p_id);6008return _texture_make_mutable(texture, p_id);6009} else if (vertex_array_owner.owns(p_id)) {6010VertexArray *vertex_array = vertex_array_owner.get_or_null(p_id);6011return _vertex_array_make_mutable(vertex_array, p_resource_id, p_resource_tracker);6012} else if (index_array_owner.owns(p_id)) {6013IndexArray *index_array = index_array_owner.get_or_null(p_id);6014return _index_array_make_mutable(index_array, p_resource_tracker);6015} else if (uniform_set_owner.owns(p_id)) {6016UniformSet *uniform_set = uniform_set_owner.get_or_null(p_id);6017return _uniform_set_make_mutable(uniform_set, p_resource_id, p_resource_tracker);6018} else {6019DEV_ASSERT(false && "Unknown resource type to make mutable.");6020return false;6021}6022}60236024bool RenderingDevice::_dependencies_make_mutable_recursive(RID p_id, RDG::ResourceTracker *p_resource_tracker) {6025bool made_mutable = false;6026HashMap<RID, HashSet<RID>>::Iterator E = dependency_map.find(p_id);6027if (E) {6028for (RID rid : E->value) {6029made_mutable = _dependency_make_mutable(rid, p_id, p_resource_tracker) || made_mutable;6030}6031}60326033return made_mutable;6034}60356036bool RenderingDevice::_dependencies_make_mutable(RID p_id, RDG::ResourceTracker *p_resource_tracker) {6037_THREAD_SAFE_METHOD_6038return _dependencies_make_mutable_recursive(p_id, p_resource_tracker);6039}60406041/**************************/6042/**** FRAME MANAGEMENT ****/6043/**************************/60446045void RenderingDevice::free(RID p_id) {6046ERR_RENDER_THREAD_GUARD();60476048_free_dependencies(p_id); // Recursively erase dependencies first, to avoid potential API problems.6049_free_internal(p_id);6050}60516052void RenderingDevice::_free_internal(RID p_id) {6053#ifdef DEV_ENABLED6054String resource_name;6055if (resource_names.has(p_id)) {6056resource_name = resource_names[p_id];6057resource_names.erase(p_id);6058}6059#endif60606061// Push everything so it's disposed of next time this frame index is processed (means, it's safe to do it).6062if (texture_owner.owns(p_id)) {6063Texture *texture = texture_owner.get_or_null(p_id);6064_check_transfer_worker_texture(texture);60656066RDG::ResourceTracker *draw_tracker = texture->draw_tracker;6067if (draw_tracker != nullptr) {6068draw_tracker->reference_count--;6069if (draw_tracker->reference_count == 0) {6070RDG::resource_tracker_free(draw_tracker);60716072if (texture->owner.is_valid() && (texture->slice_type != TEXTURE_SLICE_MAX)) {6073// If this was a texture slice, erase the tracker from the map.6074Texture *owner_texture = texture_owner.get_or_null(texture->owner);6075if (owner_texture != nullptr && owner_texture->slice_trackers != nullptr) {6076owner_texture->slice_trackers->erase(texture->slice_rect);60776078if (owner_texture->slice_trackers->is_empty()) {6079memdelete(owner_texture->slice_trackers);6080owner_texture->slice_trackers = nullptr;6081}6082}6083}6084}6085}60866087frames[frame].textures_to_dispose_of.push_back(*texture);6088texture_owner.free(p_id);6089} else if (framebuffer_owner.owns(p_id)) {6090Framebuffer *framebuffer = framebuffer_owner.get_or_null(p_id);6091frames[frame].framebuffers_to_dispose_of.push_back(*framebuffer);60926093if (framebuffer->invalidated_callback != nullptr) {6094framebuffer->invalidated_callback(framebuffer->invalidated_callback_userdata);6095}60966097framebuffer_owner.free(p_id);6098} else if (sampler_owner.owns(p_id)) {6099RDD::SamplerID sampler_driver_id = *sampler_owner.get_or_null(p_id);6100frames[frame].samplers_to_dispose_of.push_back(sampler_driver_id);6101sampler_owner.free(p_id);6102} else if (vertex_buffer_owner.owns(p_id)) {6103Buffer *vertex_buffer = vertex_buffer_owner.get_or_null(p_id);6104_check_transfer_worker_buffer(vertex_buffer);61056106RDG::resource_tracker_free(vertex_buffer->draw_tracker);6107frames[frame].buffers_to_dispose_of.push_back(*vertex_buffer);6108vertex_buffer_owner.free(p_id);6109} else if (vertex_array_owner.owns(p_id)) {6110vertex_array_owner.free(p_id);6111} else if (index_buffer_owner.owns(p_id)) {6112IndexBuffer *index_buffer = index_buffer_owner.get_or_null(p_id);6113_check_transfer_worker_buffer(index_buffer);61146115RDG::resource_tracker_free(index_buffer->draw_tracker);6116frames[frame].buffers_to_dispose_of.push_back(*index_buffer);6117index_buffer_owner.free(p_id);6118} else if (index_array_owner.owns(p_id)) {6119index_array_owner.free(p_id);6120} else if (shader_owner.owns(p_id)) {6121Shader *shader = shader_owner.get_or_null(p_id);6122if (shader->driver_id) { // Not placeholder?6123frames[frame].shaders_to_dispose_of.push_back(*shader);6124}6125shader_owner.free(p_id);6126} else if (uniform_buffer_owner.owns(p_id)) {6127Buffer *uniform_buffer = uniform_buffer_owner.get_or_null(p_id);6128_check_transfer_worker_buffer(uniform_buffer);61296130RDG::resource_tracker_free(uniform_buffer->draw_tracker);6131frames[frame].buffers_to_dispose_of.push_back(*uniform_buffer);6132uniform_buffer_owner.free(p_id);6133} else if (texture_buffer_owner.owns(p_id)) {6134Buffer *texture_buffer = texture_buffer_owner.get_or_null(p_id);6135_check_transfer_worker_buffer(texture_buffer);61366137RDG::resource_tracker_free(texture_buffer->draw_tracker);6138frames[frame].buffers_to_dispose_of.push_back(*texture_buffer);6139texture_buffer_owner.free(p_id);6140} else if (storage_buffer_owner.owns(p_id)) {6141Buffer *storage_buffer = storage_buffer_owner.get_or_null(p_id);6142_check_transfer_worker_buffer(storage_buffer);61436144RDG::resource_tracker_free(storage_buffer->draw_tracker);6145frames[frame].buffers_to_dispose_of.push_back(*storage_buffer);6146storage_buffer_owner.free(p_id);6147} else if (uniform_set_owner.owns(p_id)) {6148UniformSet *uniform_set = uniform_set_owner.get_or_null(p_id);6149frames[frame].uniform_sets_to_dispose_of.push_back(*uniform_set);6150uniform_set_owner.free(p_id);61516152if (uniform_set->invalidated_callback != nullptr) {6153uniform_set->invalidated_callback(uniform_set->invalidated_callback_userdata);6154}6155} else if (render_pipeline_owner.owns(p_id)) {6156RenderPipeline *pipeline = render_pipeline_owner.get_or_null(p_id);6157frames[frame].render_pipelines_to_dispose_of.push_back(*pipeline);6158render_pipeline_owner.free(p_id);6159} else if (compute_pipeline_owner.owns(p_id)) {6160ComputePipeline *pipeline = compute_pipeline_owner.get_or_null(p_id);6161frames[frame].compute_pipelines_to_dispose_of.push_back(*pipeline);6162compute_pipeline_owner.free(p_id);6163} else {6164#ifdef DEV_ENABLED6165ERR_PRINT("Attempted to free invalid ID: " + itos(p_id.get_id()) + " " + resource_name);6166#else6167ERR_PRINT("Attempted to free invalid ID: " + itos(p_id.get_id()));6168#endif6169}61706171frames_pending_resources_for_processing = uint32_t(frames.size());6172}61736174// The full list of resources that can be named is in the VkObjectType enum.6175// We just expose the resources that are owned and can be accessed easily.6176void RenderingDevice::set_resource_name(RID p_id, const String &p_name) {6177_THREAD_SAFE_METHOD_61786179if (texture_owner.owns(p_id)) {6180Texture *texture = texture_owner.get_or_null(p_id);6181driver->set_object_name(RDD::OBJECT_TYPE_TEXTURE, texture->driver_id, p_name);6182} else if (framebuffer_owner.owns(p_id)) {6183//Framebuffer *framebuffer = framebuffer_owner.get_or_null(p_id);6184// Not implemented for now as the relationship between Framebuffer and RenderPass is very complex.6185} else if (sampler_owner.owns(p_id)) {6186RDD::SamplerID sampler_driver_id = *sampler_owner.get_or_null(p_id);6187driver->set_object_name(RDD::OBJECT_TYPE_SAMPLER, sampler_driver_id, p_name);6188} else if (vertex_buffer_owner.owns(p_id)) {6189Buffer *vertex_buffer = vertex_buffer_owner.get_or_null(p_id);6190driver->set_object_name(RDD::OBJECT_TYPE_BUFFER, vertex_buffer->driver_id, p_name);6191} else if (index_buffer_owner.owns(p_id)) {6192IndexBuffer *index_buffer = index_buffer_owner.get_or_null(p_id);6193driver->set_object_name(RDD::OBJECT_TYPE_BUFFER, index_buffer->driver_id, p_name);6194} else if (shader_owner.owns(p_id)) {6195Shader *shader = shader_owner.get_or_null(p_id);6196driver->set_object_name(RDD::OBJECT_TYPE_SHADER, shader->driver_id, p_name);6197} else if (uniform_buffer_owner.owns(p_id)) {6198Buffer *uniform_buffer = uniform_buffer_owner.get_or_null(p_id);6199driver->set_object_name(RDD::OBJECT_TYPE_BUFFER, uniform_buffer->driver_id, p_name);6200} else if (texture_buffer_owner.owns(p_id)) {6201Buffer *texture_buffer = texture_buffer_owner.get_or_null(p_id);6202driver->set_object_name(RDD::OBJECT_TYPE_BUFFER, texture_buffer->driver_id, p_name);6203} else if (storage_buffer_owner.owns(p_id)) {6204Buffer *storage_buffer = storage_buffer_owner.get_or_null(p_id);6205driver->set_object_name(RDD::OBJECT_TYPE_BUFFER, storage_buffer->driver_id, p_name);6206} else if (uniform_set_owner.owns(p_id)) {6207UniformSet *uniform_set = uniform_set_owner.get_or_null(p_id);6208driver->set_object_name(RDD::OBJECT_TYPE_UNIFORM_SET, uniform_set->driver_id, p_name);6209} else if (render_pipeline_owner.owns(p_id)) {6210RenderPipeline *pipeline = render_pipeline_owner.get_or_null(p_id);6211driver->set_object_name(RDD::OBJECT_TYPE_PIPELINE, pipeline->driver_id, p_name);6212} else if (compute_pipeline_owner.owns(p_id)) {6213ComputePipeline *pipeline = compute_pipeline_owner.get_or_null(p_id);6214driver->set_object_name(RDD::OBJECT_TYPE_PIPELINE, pipeline->driver_id, p_name);6215} else {6216ERR_PRINT("Attempted to name invalid ID: " + itos(p_id.get_id()));6217return;6218}6219#ifdef DEV_ENABLED6220resource_names[p_id] = p_name;6221#endif6222}62236224void RenderingDevice::_draw_command_begin_label(String p_label_name, const Color &p_color) {6225draw_command_begin_label(p_label_name.utf8().span(), p_color);6226}62276228void RenderingDevice::draw_command_begin_label(const Span<char> p_label_name, const Color &p_color) {6229ERR_RENDER_THREAD_GUARD();62306231if (!context->is_debug_utils_enabled()) {6232return;6233}62346235draw_graph.begin_label(p_label_name, p_color);6236}62376238#ifndef DISABLE_DEPRECATED6239void RenderingDevice::draw_command_insert_label(String p_label_name, const Color &p_color) {6240WARN_PRINT("Deprecated. Inserting labels no longer applies due to command reordering.");6241}6242#endif62436244void RenderingDevice::draw_command_end_label() {6245ERR_RENDER_THREAD_GUARD();62466247draw_graph.end_label();6248}62496250String RenderingDevice::get_device_vendor_name() const {6251return _get_device_vendor_name(device);6252}62536254String RenderingDevice::get_device_name() const {6255return device.name;6256}62576258RenderingDevice::DeviceType RenderingDevice::get_device_type() const {6259return DeviceType(device.type);6260}62616262String RenderingDevice::get_device_api_name() const {6263return driver->get_api_name();6264}62656266bool RenderingDevice::is_composite_alpha_supported() const {6267return driver->is_composite_alpha_supported(main_queue);6268}62696270String RenderingDevice::get_device_api_version() const {6271return driver->get_api_version();6272}62736274String RenderingDevice::get_device_pipeline_cache_uuid() const {6275return driver->get_pipeline_cache_uuid();6276}62776278void RenderingDevice::swap_buffers(bool p_present) {6279ERR_RENDER_THREAD_GUARD();62806281_end_frame();6282_execute_frame(p_present);62836284// Advance to the next frame and begin recording again.6285frame = (frame + 1) % frames.size();62866287_begin_frame(true);6288}62896290void RenderingDevice::submit() {6291ERR_RENDER_THREAD_GUARD();6292ERR_FAIL_COND_MSG(is_main_instance, "Only local devices can submit and sync.");6293ERR_FAIL_COND_MSG(local_device_processing, "device already submitted, call sync to wait until done.");62946295_end_frame();6296_execute_frame(false);6297local_device_processing = true;6298}62996300void RenderingDevice::sync() {6301ERR_RENDER_THREAD_GUARD();6302ERR_FAIL_COND_MSG(is_main_instance, "Only local devices can submit and sync.");6303ERR_FAIL_COND_MSG(!local_device_processing, "sync can only be called after a submit");63046305_begin_frame(true);6306local_device_processing = false;6307}63086309void RenderingDevice::_free_pending_resources(int p_frame) {6310// Free in dependency usage order, so nothing weird happens.6311// Pipelines.6312while (frames[p_frame].render_pipelines_to_dispose_of.front()) {6313RenderPipeline *pipeline = &frames[p_frame].render_pipelines_to_dispose_of.front()->get();63146315driver->pipeline_free(pipeline->driver_id);63166317frames[p_frame].render_pipelines_to_dispose_of.pop_front();6318}63196320while (frames[p_frame].compute_pipelines_to_dispose_of.front()) {6321ComputePipeline *pipeline = &frames[p_frame].compute_pipelines_to_dispose_of.front()->get();63226323driver->pipeline_free(pipeline->driver_id);63246325frames[p_frame].compute_pipelines_to_dispose_of.pop_front();6326}63276328// Uniform sets.6329while (frames[p_frame].uniform_sets_to_dispose_of.front()) {6330UniformSet *uniform_set = &frames[p_frame].uniform_sets_to_dispose_of.front()->get();63316332driver->uniform_set_free(uniform_set->driver_id);63336334frames[p_frame].uniform_sets_to_dispose_of.pop_front();6335}63366337// Shaders.6338while (frames[p_frame].shaders_to_dispose_of.front()) {6339Shader *shader = &frames[p_frame].shaders_to_dispose_of.front()->get();63406341driver->shader_free(shader->driver_id);63426343frames[p_frame].shaders_to_dispose_of.pop_front();6344}63456346// Samplers.6347while (frames[p_frame].samplers_to_dispose_of.front()) {6348RDD::SamplerID sampler = frames[p_frame].samplers_to_dispose_of.front()->get();63496350driver->sampler_free(sampler);63516352frames[p_frame].samplers_to_dispose_of.pop_front();6353}63546355// Framebuffers.6356while (frames[p_frame].framebuffers_to_dispose_of.front()) {6357Framebuffer *framebuffer = &frames[p_frame].framebuffers_to_dispose_of.front()->get();6358draw_graph.framebuffer_cache_free(driver, framebuffer->framebuffer_cache);6359frames[p_frame].framebuffers_to_dispose_of.pop_front();6360}63616362// Textures.6363while (frames[p_frame].textures_to_dispose_of.front()) {6364Texture *texture = &frames[p_frame].textures_to_dispose_of.front()->get();6365if (texture->bound) {6366WARN_PRINT("Deleted a texture while it was bound.");6367}63686369_texture_free_shared_fallback(texture);63706371texture_memory -= driver->texture_get_allocation_size(texture->driver_id);6372driver->texture_free(texture->driver_id);63736374frames[p_frame].textures_to_dispose_of.pop_front();6375}63766377// Buffers.6378while (frames[p_frame].buffers_to_dispose_of.front()) {6379Buffer &buffer = frames[p_frame].buffers_to_dispose_of.front()->get();6380driver->buffer_free(buffer.driver_id);6381buffer_memory -= buffer.size;63826383frames[p_frame].buffers_to_dispose_of.pop_front();6384}63856386if (frames_pending_resources_for_processing > 0u) {6387--frames_pending_resources_for_processing;6388}6389}63906391uint32_t RenderingDevice::get_frame_delay() const {6392return frames.size();6393}63946395uint64_t RenderingDevice::get_memory_usage(MemoryType p_type) const {6396switch (p_type) {6397case MEMORY_BUFFERS: {6398return buffer_memory;6399}6400case MEMORY_TEXTURES: {6401return texture_memory;6402}6403case MEMORY_TOTAL: {6404return driver->get_total_memory_used();6405}6406default: {6407DEV_ASSERT(false);6408return 0;6409}6410}6411}64126413void RenderingDevice::_begin_frame(bool p_presented) {6414// Before writing to this frame, wait for it to be finished.6415_stall_for_frame(frame);64166417if (command_pool_reset_enabled) {6418bool reset = driver->command_pool_reset(frames[frame].command_pool);6419ERR_FAIL_COND(!reset);6420}64216422if (p_presented) {6423update_perf_report();6424driver->linear_uniform_set_pools_reset(frame);6425}64266427// Begin recording on the frame's command buffers.6428driver->begin_segment(frame, frames_drawn++);6429driver->command_buffer_begin(frames[frame].command_buffer);64306431// Reset the graph.6432draw_graph.begin();64336434// Erase pending resources.6435_free_pending_resources(frame);64366437// Advance staging buffers if used.6438if (upload_staging_buffers.used) {6439upload_staging_buffers.current = (upload_staging_buffers.current + 1) % upload_staging_buffers.blocks.size();6440upload_staging_buffers.used = false;6441}64426443if (download_staging_buffers.used) {6444download_staging_buffers.current = (download_staging_buffers.current + 1) % download_staging_buffers.blocks.size();6445download_staging_buffers.used = false;6446}64476448if (frames[frame].timestamp_count) {6449driver->timestamp_query_pool_get_results(frames[frame].timestamp_pool, frames[frame].timestamp_count, frames[frame].timestamp_result_values.ptr());6450driver->command_timestamp_query_pool_reset(frames[frame].command_buffer, frames[frame].timestamp_pool, frames[frame].timestamp_count);6451SWAP(frames[frame].timestamp_names, frames[frame].timestamp_result_names);6452SWAP(frames[frame].timestamp_cpu_values, frames[frame].timestamp_cpu_result_values);6453}64546455frames[frame].timestamp_result_count = frames[frame].timestamp_count;6456frames[frame].timestamp_count = 0;6457frames[frame].index = Engine::get_singleton()->get_frames_drawn();6458}64596460void RenderingDevice::_end_frame() {6461if (draw_list.active) {6462ERR_PRINT("Found open draw list at the end of the frame, this should never happen (further drawing will likely not work).");6463}64646465if (compute_list.active) {6466ERR_PRINT("Found open compute list at the end of the frame, this should never happen (further compute will likely not work).");6467}64686469// The command buffer must be copied into a stack variable as the driver workarounds can change the command buffer in use.6470RDD::CommandBufferID command_buffer = frames[frame].command_buffer;6471_submit_transfer_workers(command_buffer);6472_submit_transfer_barriers(command_buffer);64736474draw_graph.end(RENDER_GRAPH_REORDER, RENDER_GRAPH_FULL_BARRIERS, command_buffer, frames[frame].command_buffer_pool);6475driver->command_buffer_end(command_buffer);6476driver->end_segment();6477}64786479void RenderingDevice::execute_chained_cmds(bool p_present_swap_chain, RenderingDeviceDriver::FenceID p_draw_fence,6480RenderingDeviceDriver::SemaphoreID p_dst_draw_semaphore_to_signal) {6481// Execute command buffers and use semaphores to wait on the execution of the previous one.6482// Normally there's only one command buffer, but driver workarounds can force situations where6483// there'll be more.6484uint32_t command_buffer_count = 1;6485RDG::CommandBufferPool &buffer_pool = frames[frame].command_buffer_pool;6486if (buffer_pool.buffers_used > 0) {6487command_buffer_count += buffer_pool.buffers_used;6488buffer_pool.buffers_used = 0;6489}64906491thread_local LocalVector<RDD::SwapChainID> swap_chains;6492swap_chains.clear();64936494// Instead of having just one command; we have potentially many (which had to be split due to an6495// Adreno workaround on mobile, only if the workaround is active). Thus we must execute all of them6496// and chain them together via semaphores as dependent executions.6497thread_local LocalVector<RDD::SemaphoreID> wait_semaphores;6498wait_semaphores = frames[frame].semaphores_to_wait_on;64996500for (uint32_t i = 0; i < command_buffer_count; i++) {6501RDD::CommandBufferID command_buffer;6502RDD::SemaphoreID signal_semaphore;6503RDD::FenceID signal_fence;6504if (i > 0) {6505command_buffer = buffer_pool.buffers[i - 1];6506} else {6507command_buffer = frames[frame].command_buffer;6508}65096510if (i == (command_buffer_count - 1)) {6511// This is the last command buffer, it should signal the semaphore & fence.6512signal_semaphore = p_dst_draw_semaphore_to_signal;6513signal_fence = p_draw_fence;65146515if (p_present_swap_chain) {6516// Just present the swap chains as part of the last command execution.6517swap_chains = frames[frame].swap_chains_to_present;6518}6519} else {6520signal_semaphore = buffer_pool.semaphores[i];6521// Semaphores always need to be signaled if it's not the last command buffer.6522}65236524driver->command_queue_execute_and_present(main_queue, wait_semaphores, command_buffer,6525signal_semaphore ? signal_semaphore : VectorView<RDD::SemaphoreID>(), signal_fence,6526swap_chains);65276528// Make the next command buffer wait on the semaphore signaled by this one.6529wait_semaphores.resize(1);6530wait_semaphores[0] = signal_semaphore;6531}65326533frames[frame].semaphores_to_wait_on.clear();6534}65356536void RenderingDevice::_execute_frame(bool p_present) {6537// Check whether this frame should present the swap chains and in which queue.6538const bool frame_can_present = p_present && !frames[frame].swap_chains_to_present.is_empty();6539const bool separate_present_queue = main_queue != present_queue;65406541// The semaphore is required if the frame can be presented and a separate present queue is used;6542// since the separate queue will wait for that semaphore before presenting.6543const RDD::SemaphoreID semaphore = (frame_can_present && separate_present_queue)6544? frames[frame].semaphore6545: RDD::SemaphoreID(nullptr);6546const bool present_swap_chain = frame_can_present && !separate_present_queue;65476548execute_chained_cmds(present_swap_chain, frames[frame].fence, semaphore);6549// Indicate the fence has been signaled so the next time the frame's contents need to be6550// used, the CPU needs to wait on the work to be completed.6551frames[frame].fence_signaled = true;65526553if (frame_can_present) {6554if (separate_present_queue) {6555// Issue the presentation separately if the presentation queue is different from the main queue.6556driver->command_queue_execute_and_present(present_queue, frames[frame].semaphore, {}, {}, {}, frames[frame].swap_chains_to_present);6557}65586559frames[frame].swap_chains_to_present.clear();6560}6561}65626563void RenderingDevice::_stall_for_frame(uint32_t p_frame) {6564thread_local PackedByteArray packed_byte_array;65656566if (frames[p_frame].fence_signaled) {6567driver->fence_wait(frames[p_frame].fence);6568frames[p_frame].fence_signaled = false;65696570// Flush any pending requests for asynchronous buffer downloads.6571if (!frames[p_frame].download_buffer_get_data_requests.is_empty()) {6572for (uint32_t i = 0; i < frames[p_frame].download_buffer_get_data_requests.size(); i++) {6573const BufferGetDataRequest &request = frames[p_frame].download_buffer_get_data_requests[i];6574packed_byte_array.resize(request.size);65756576uint32_t array_offset = 0;6577for (uint32_t j = 0; j < request.frame_local_count; j++) {6578uint32_t local_index = request.frame_local_index + j;6579const RDD::BufferCopyRegion ®ion = frames[p_frame].download_buffer_copy_regions[local_index];6580uint8_t *buffer_data = driver->buffer_map(frames[p_frame].download_buffer_staging_buffers[local_index]);6581memcpy(&packed_byte_array.write[array_offset], &buffer_data[region.dst_offset], region.size);6582driver->buffer_unmap(frames[p_frame].download_buffer_staging_buffers[local_index]);6583array_offset += region.size;6584}65856586request.callback.call(packed_byte_array);6587}65886589frames[p_frame].download_buffer_staging_buffers.clear();6590frames[p_frame].download_buffer_copy_regions.clear();6591frames[p_frame].download_buffer_get_data_requests.clear();6592}65936594// Flush any pending requests for asynchronous texture downloads.6595if (!frames[p_frame].download_texture_get_data_requests.is_empty()) {6596uint32_t pitch_step = driver->api_trait_get(RDD::API_TRAIT_TEXTURE_DATA_ROW_PITCH_STEP);6597for (uint32_t i = 0; i < frames[p_frame].download_texture_get_data_requests.size(); i++) {6598const TextureGetDataRequest &request = frames[p_frame].download_texture_get_data_requests[i];6599uint32_t texture_size = get_image_format_required_size(request.format, request.width, request.height, request.depth, request.mipmaps);6600packed_byte_array.resize(texture_size);66016602// Find the block size of the texture's format.6603uint32_t block_w = 0;6604uint32_t block_h = 0;6605get_compressed_image_format_block_dimensions(request.format, block_w, block_h);66066607uint32_t block_size = get_compressed_image_format_block_byte_size(request.format);6608uint32_t pixel_size = get_image_format_pixel_size(request.format);6609uint32_t pixel_rshift = get_compressed_image_format_pixel_rshift(request.format);6610uint32_t region_size = texture_download_region_size_px;66116612for (uint32_t j = 0; j < request.frame_local_count; j++) {6613uint32_t local_index = request.frame_local_index + j;6614const RDD::BufferTextureCopyRegion ®ion = frames[p_frame].download_buffer_texture_copy_regions[local_index];6615uint32_t w = STEPIFY(request.width >> region.texture_subresources.mipmap, block_w);6616uint32_t h = STEPIFY(request.height >> region.texture_subresources.mipmap, block_h);6617uint32_t region_w = MIN(region_size, w - region.texture_offset.x);6618uint32_t region_h = MIN(region_size, h - region.texture_offset.y);6619uint32_t region_pitch = (region_w * pixel_size * block_w) >> pixel_rshift;6620region_pitch = STEPIFY(region_pitch, pitch_step);66216622uint8_t *buffer_data = driver->buffer_map(frames[p_frame].download_texture_staging_buffers[local_index]);6623const uint8_t *read_ptr = buffer_data + region.buffer_offset;6624uint8_t *write_ptr = packed_byte_array.ptrw() + frames[p_frame].download_texture_mipmap_offsets[local_index];6625uint32_t unit_size = pixel_size;6626if (block_w != 1 || block_h != 1) {6627unit_size = block_size;6628}66296630write_ptr += ((region.texture_offset.y / block_h) * (w / block_w) + (region.texture_offset.x / block_w)) * unit_size;6631for (uint32_t y = region_h / block_h; y > 0; y--) {6632memcpy(write_ptr, read_ptr, (region_w / block_w) * unit_size);6633write_ptr += (w / block_w) * unit_size;6634read_ptr += region_pitch;6635}66366637driver->buffer_unmap(frames[p_frame].download_texture_staging_buffers[local_index]);6638}66396640request.callback.call(packed_byte_array);6641}66426643frames[p_frame].download_texture_staging_buffers.clear();6644frames[p_frame].download_buffer_texture_copy_regions.clear();6645frames[p_frame].download_texture_mipmap_offsets.clear();6646frames[p_frame].download_texture_get_data_requests.clear();6647}6648}6649}66506651void RenderingDevice::_stall_for_previous_frames() {6652for (uint32_t i = 0; i < frames.size(); i++) {6653_stall_for_frame(i);6654}6655}66566657void RenderingDevice::_flush_and_stall_for_all_frames() {6658_stall_for_previous_frames();6659_end_frame();6660_execute_frame(false);6661_begin_frame();6662}66636664Error RenderingDevice::initialize(RenderingContextDriver *p_context, DisplayServer::WindowID p_main_window) {6665ERR_RENDER_THREAD_GUARD_V(ERR_UNAVAILABLE);66666667Error err;6668RenderingContextDriver::SurfaceID main_surface = 0;6669is_main_instance = (singleton == this) && (p_main_window != DisplayServer::INVALID_WINDOW_ID);6670if (p_main_window != DisplayServer::INVALID_WINDOW_ID) {6671// Retrieve the surface from the main window if it was specified.6672main_surface = p_context->surface_get_from_window(p_main_window);6673ERR_FAIL_COND_V(main_surface == 0, FAILED);6674}66756676context = p_context;6677driver = context->driver_create();66786679print_verbose("Devices:");6680int32_t device_index = Engine::get_singleton()->get_gpu_index();6681const uint32_t device_count = context->device_get_count();6682const bool detect_device = (device_index < 0) || (device_index >= int32_t(device_count));6683uint32_t device_type_score = 0;6684for (uint32_t i = 0; i < device_count; i++) {6685RenderingContextDriver::Device device_option = context->device_get(i);6686String name = device_option.name;6687String vendor = _get_device_vendor_name(device_option);6688String type = _get_device_type_name(device_option);6689bool present_supported = main_surface != 0 ? context->device_supports_present(i, main_surface) : false;6690print_verbose(" #" + itos(i) + ": " + vendor + " " + name + " - " + (present_supported ? "Supported" : "Unsupported") + ", " + type);6691if (detect_device && (present_supported || main_surface == 0)) {6692// If a window was specified, present must be supported by the device to be available as an option.6693// Assign a score for each type of device and prefer the device with the higher score.6694uint32_t option_score = _get_device_type_score(device_option);6695if (option_score > device_type_score) {6696device_index = i;6697device_type_score = option_score;6698}6699}6700}67016702ERR_FAIL_COND_V_MSG((device_index < 0) || (device_index >= int32_t(device_count)), ERR_CANT_CREATE, "None of the devices supports both graphics and present queues.");67036704uint32_t frame_count = 1;6705if (main_surface != 0) {6706frame_count = MAX(2U, uint32_t(GLOBAL_GET("rendering/rendering_device/vsync/frame_queue_size")));6707}67086709frame = 0;6710max_timestamp_query_elements = GLOBAL_GET("debug/settings/profiler/max_timestamp_query_elements");67116712device = context->device_get(device_index);6713err = driver->initialize(device_index, frame_count);6714ERR_FAIL_COND_V_MSG(err != OK, FAILED, "Failed to initialize driver for device.");67156716if (is_main_instance) {6717// Only the singleton instance with a display should print this information.6718String rendering_method;6719if (OS::get_singleton()->get_current_rendering_method() == "mobile") {6720rendering_method = "Forward Mobile";6721} else {6722rendering_method = "Forward+";6723}67246725// Output our device version.6726Engine::get_singleton()->print_header(vformat("%s %s - %s - Using Device #%d: %s - %s", get_device_api_name(), get_device_api_version(), rendering_method, device_index, _get_device_vendor_name(device), device.name));6727}67286729// Pick the main queue family. It is worth noting we explicitly do not request the transfer bit, as apparently the specification defines6730// that the existence of either the graphics or compute bit implies that the queue can also do transfer operations, but it is optional6731// to indicate whether it supports them or not with the dedicated transfer bit if either is set.6732BitField<RDD::CommandQueueFamilyBits> main_queue_bits = {};6733main_queue_bits.set_flag(RDD::COMMAND_QUEUE_FAMILY_GRAPHICS_BIT);6734main_queue_bits.set_flag(RDD::COMMAND_QUEUE_FAMILY_COMPUTE_BIT);67356736#if !FORCE_SEPARATE_PRESENT_QUEUE6737// Needing to use a separate queue for presentation is an edge case that remains to be seen what hardware triggers it at all.6738main_queue_family = driver->command_queue_family_get(main_queue_bits, main_surface);6739if (!main_queue_family && (main_surface != 0))6740#endif6741{6742// If it was not possible to find a main queue that supports the surface, we attempt to get two different queues instead.6743main_queue_family = driver->command_queue_family_get(main_queue_bits);6744present_queue_family = driver->command_queue_family_get(BitField<RDD::CommandQueueFamilyBits>(), main_surface);6745ERR_FAIL_COND_V(!present_queue_family, FAILED);6746}67476748ERR_FAIL_COND_V(!main_queue_family, FAILED);67496750// Create the main queue.6751main_queue = driver->command_queue_create(main_queue_family, true);6752ERR_FAIL_COND_V(!main_queue, FAILED);67536754transfer_queue_family = driver->command_queue_family_get(RDD::COMMAND_QUEUE_FAMILY_TRANSFER_BIT);6755if (transfer_queue_family) {6756// Create the transfer queue.6757transfer_queue = driver->command_queue_create(transfer_queue_family);6758ERR_FAIL_COND_V(!transfer_queue, FAILED);6759} else {6760// Use main queue as the transfer queue.6761transfer_queue = main_queue;6762transfer_queue_family = main_queue_family;6763}67646765if (present_queue_family) {6766// Create the present queue.6767present_queue = driver->command_queue_create(present_queue_family);6768ERR_FAIL_COND_V(!present_queue, FAILED);6769} else {6770// Use main queue as the present queue.6771present_queue = main_queue;6772present_queue_family = main_queue_family;6773}67746775// Use the processor count as the max amount of transfer workers that can be created.6776transfer_worker_pool_max_size = OS::get_singleton()->get_processor_count();67776778frames.resize(frame_count);67796780// Create data for all the frames.6781for (uint32_t i = 0; i < frames.size(); i++) {6782frames[i].index = 0;67836784// Create command pool, command buffers, semaphores and fences.6785frames[i].command_pool = driver->command_pool_create(main_queue_family, RDD::COMMAND_BUFFER_TYPE_PRIMARY);6786ERR_FAIL_COND_V(!frames[i].command_pool, FAILED);6787frames[i].command_buffer = driver->command_buffer_create(frames[i].command_pool);6788ERR_FAIL_COND_V(!frames[i].command_buffer, FAILED);6789frames[i].semaphore = driver->semaphore_create();6790ERR_FAIL_COND_V(!frames[i].semaphore, FAILED);6791frames[i].fence = driver->fence_create();6792ERR_FAIL_COND_V(!frames[i].fence, FAILED);6793frames[i].fence_signaled = false;67946795// Create query pool.6796frames[i].timestamp_pool = driver->timestamp_query_pool_create(max_timestamp_query_elements);6797frames[i].timestamp_names.resize(max_timestamp_query_elements);6798frames[i].timestamp_cpu_values.resize(max_timestamp_query_elements);6799frames[i].timestamp_count = 0;6800frames[i].timestamp_result_names.resize(max_timestamp_query_elements);6801frames[i].timestamp_cpu_result_values.resize(max_timestamp_query_elements);6802frames[i].timestamp_result_values.resize(max_timestamp_query_elements);6803frames[i].timestamp_result_count = 0;68046805// Assign the main queue family and command pool to the command buffer pool.6806frames[i].command_buffer_pool.pool = frames[i].command_pool;68076808// Create the semaphores for the transfer workers.6809frames[i].transfer_worker_semaphores.resize(transfer_worker_pool_max_size);6810for (uint32_t j = 0; j < transfer_worker_pool_max_size; j++) {6811frames[i].transfer_worker_semaphores[j] = driver->semaphore_create();6812ERR_FAIL_COND_V(!frames[i].transfer_worker_semaphores[j], FAILED);6813}6814}68156816// Start from frame count, so everything else is immediately old.6817frames_drawn = frames.size();68186819// Initialize recording on the first frame.6820driver->begin_segment(frame, frames_drawn++);6821driver->command_buffer_begin(frames[0].command_buffer);68226823// Create draw graph and start it initialized as well.6824draw_graph.initialize(driver, device, &_render_pass_create_from_graph, frames.size(), main_queue_family, SECONDARY_COMMAND_BUFFERS_PER_FRAME);6825draw_graph.begin();68266827for (uint32_t i = 0; i < frames.size(); i++) {6828// Reset all queries in a query pool before doing any operations with them..6829driver->command_timestamp_query_pool_reset(frames[0].command_buffer, frames[i].timestamp_pool, max_timestamp_query_elements);6830}68316832// Convert block size from KB.6833upload_staging_buffers.block_size = GLOBAL_GET("rendering/rendering_device/staging_buffer/block_size_kb");6834upload_staging_buffers.block_size = MAX(4u, upload_staging_buffers.block_size);6835upload_staging_buffers.block_size *= 1024;68366837// Convert staging buffer size from MB.6838upload_staging_buffers.max_size = GLOBAL_GET("rendering/rendering_device/staging_buffer/max_size_mb");6839upload_staging_buffers.max_size = MAX(1u, upload_staging_buffers.max_size);6840upload_staging_buffers.max_size *= 1024 * 1024;6841upload_staging_buffers.max_size = MAX(upload_staging_buffers.max_size, upload_staging_buffers.block_size * 4);68426843// Copy the sizes to the download staging buffers.6844download_staging_buffers.block_size = upload_staging_buffers.block_size;6845download_staging_buffers.max_size = upload_staging_buffers.max_size;68466847texture_upload_region_size_px = GLOBAL_GET("rendering/rendering_device/staging_buffer/texture_upload_region_size_px");6848texture_upload_region_size_px = nearest_power_of_2_templated(texture_upload_region_size_px);68496850texture_download_region_size_px = GLOBAL_GET("rendering/rendering_device/staging_buffer/texture_download_region_size_px");6851texture_download_region_size_px = nearest_power_of_2_templated(texture_download_region_size_px);68526853// Ensure current staging block is valid and at least one per frame exists.6854upload_staging_buffers.current = 0;6855upload_staging_buffers.used = false;6856upload_staging_buffers.usage_bits = RDD::BUFFER_USAGE_TRANSFER_FROM_BIT;68576858download_staging_buffers.current = 0;6859download_staging_buffers.used = false;6860download_staging_buffers.usage_bits = RDD::BUFFER_USAGE_TRANSFER_TO_BIT;68616862for (uint32_t i = 0; i < frames.size(); i++) {6863// Staging was never used, create the blocks.6864err = _insert_staging_block(upload_staging_buffers);6865ERR_FAIL_COND_V(err, FAILED);68666867err = _insert_staging_block(download_staging_buffers);6868ERR_FAIL_COND_V(err, FAILED);6869}68706871draw_list = DrawList();6872compute_list = ComputeList();68736874bool project_pipeline_cache_enable = GLOBAL_GET("rendering/rendering_device/pipeline_cache/enable");6875if (is_main_instance && project_pipeline_cache_enable) {6876// Only the instance that is not a local device and is also the singleton is allowed to manage a pipeline cache.6877pipeline_cache_file_path = vformat("user://vulkan/pipelines.%s.%s",6878OS::get_singleton()->get_current_rendering_method(),6879device.name.validate_filename().replace_char(' ', '_').to_lower());6880if (Engine::get_singleton()->is_editor_hint()) {6881pipeline_cache_file_path += ".editor";6882}6883pipeline_cache_file_path += ".cache";68846885Vector<uint8_t> cache_data = _load_pipeline_cache();6886pipeline_cache_enabled = driver->pipeline_cache_create(cache_data);6887if (pipeline_cache_enabled) {6888pipeline_cache_size = driver->pipeline_cache_query_size();6889print_verbose(vformat("Startup PSO cache (%.1f MiB)", pipeline_cache_size / (1024.0f * 1024.0f)));6890}6891}68926893// Find the best method available for VRS on the current hardware.6894_vrs_detect_method();68956896return OK;6897}68986899Vector<uint8_t> RenderingDevice::_load_pipeline_cache() {6900DirAccess::make_dir_recursive_absolute(pipeline_cache_file_path.get_base_dir());69016902if (FileAccess::exists(pipeline_cache_file_path)) {6903Error file_error;6904Vector<uint8_t> file_data = FileAccess::get_file_as_bytes(pipeline_cache_file_path, &file_error);6905return file_data;6906} else {6907return Vector<uint8_t>();6908}6909}69106911void RenderingDevice::_update_pipeline_cache(bool p_closing) {6912_THREAD_SAFE_METHOD_69136914{6915bool still_saving = pipeline_cache_save_task != WorkerThreadPool::INVALID_TASK_ID && !WorkerThreadPool::get_singleton()->is_task_completed(pipeline_cache_save_task);6916if (still_saving) {6917if (p_closing) {6918WorkerThreadPool::get_singleton()->wait_for_task_completion(pipeline_cache_save_task);6919pipeline_cache_save_task = WorkerThreadPool::INVALID_TASK_ID;6920} else {6921// We can't save until the currently running save is done. We'll retry next time; worst case, we'll save when exiting.6922return;6923}6924}6925}69266927{6928size_t new_pipelines_cache_size = driver->pipeline_cache_query_size();6929ERR_FAIL_COND(!new_pipelines_cache_size);6930size_t difference = new_pipelines_cache_size - pipeline_cache_size;69316932bool must_save = false;69336934if (p_closing) {6935must_save = difference > 0;6936} else {6937float save_interval = GLOBAL_GET("rendering/rendering_device/pipeline_cache/save_chunk_size_mb");6938must_save = difference > 0 && difference / (1024.0f * 1024.0f) >= save_interval;6939}69406941if (must_save) {6942pipeline_cache_size = new_pipelines_cache_size;6943} else {6944return;6945}6946}69476948if (p_closing) {6949_save_pipeline_cache(this);6950} else {6951pipeline_cache_save_task = WorkerThreadPool::get_singleton()->add_native_task(&_save_pipeline_cache, this, false, "PipelineCacheSave");6952}6953}69546955void RenderingDevice::_save_pipeline_cache(void *p_data) {6956RenderingDevice *self = static_cast<RenderingDevice *>(p_data);69576958self->_thread_safe_.lock();6959Vector<uint8_t> cache_blob = self->driver->pipeline_cache_serialize();6960self->_thread_safe_.unlock();69616962if (cache_blob.is_empty()) {6963return;6964}6965print_verbose(vformat("Updated PSO cache (%.1f MiB)", cache_blob.size() / (1024.0f * 1024.0f)));69666967Ref<FileAccess> f = FileAccess::open(self->pipeline_cache_file_path, FileAccess::WRITE, nullptr);6968if (f.is_valid()) {6969f->store_buffer(cache_blob);6970}6971}69726973template <typename T>6974void RenderingDevice::_free_rids(T &p_owner, const char *p_type) {6975LocalVector<RID> owned = p_owner.get_owned_list();6976if (owned.size()) {6977if (owned.size() == 1) {6978WARN_PRINT(vformat("1 RID of type \"%s\" was leaked.", p_type));6979} else {6980WARN_PRINT(vformat("%d RIDs of type \"%s\" were leaked.", owned.size(), p_type));6981}6982for (const RID &rid : owned) {6983#ifdef DEV_ENABLED6984if (resource_names.has(rid)) {6985print_line(String(" - ") + resource_names[rid]);6986}6987#endif6988free(rid);6989}6990}6991}69926993void RenderingDevice::capture_timestamp(const String &p_name) {6994ERR_RENDER_THREAD_GUARD();69956996ERR_FAIL_COND_MSG(draw_list.active && draw_list.state.draw_count > 0, "Capturing timestamps during draw list creation is not allowed. Offending timestamp was: " + p_name);6997ERR_FAIL_COND_MSG(compute_list.active && compute_list.state.dispatch_count > 0, "Capturing timestamps during compute list creation is not allowed. Offending timestamp was: " + p_name);6998ERR_FAIL_COND_MSG(frames[frame].timestamp_count >= max_timestamp_query_elements, vformat("Tried capturing more timestamps than the configured maximum (%d). You can increase this limit in the project settings under 'Debug/Settings' called 'Max Timestamp Query Elements'.", max_timestamp_query_elements));69997000draw_graph.add_capture_timestamp(frames[frame].timestamp_pool, frames[frame].timestamp_count);70017002frames[frame].timestamp_names[frames[frame].timestamp_count] = p_name;7003frames[frame].timestamp_cpu_values[frames[frame].timestamp_count] = OS::get_singleton()->get_ticks_usec();7004frames[frame].timestamp_count++;7005}70067007uint64_t RenderingDevice::get_driver_resource(DriverResource p_resource, RID p_rid, uint64_t p_index) {7008ERR_RENDER_THREAD_GUARD_V(0);70097010uint64_t driver_id = 0;7011switch (p_resource) {7012case DRIVER_RESOURCE_LOGICAL_DEVICE:7013case DRIVER_RESOURCE_PHYSICAL_DEVICE:7014case DRIVER_RESOURCE_TOPMOST_OBJECT:7015break;7016case DRIVER_RESOURCE_COMMAND_QUEUE:7017driver_id = main_queue.id;7018break;7019case DRIVER_RESOURCE_QUEUE_FAMILY:7020driver_id = main_queue_family.id;7021break;7022case DRIVER_RESOURCE_TEXTURE:7023case DRIVER_RESOURCE_TEXTURE_VIEW:7024case DRIVER_RESOURCE_TEXTURE_DATA_FORMAT: {7025Texture *tex = texture_owner.get_or_null(p_rid);7026ERR_FAIL_NULL_V(tex, 0);70277028driver_id = tex->driver_id.id;7029} break;7030case DRIVER_RESOURCE_SAMPLER: {7031RDD::SamplerID *sampler_driver_id = sampler_owner.get_or_null(p_rid);7032ERR_FAIL_NULL_V(sampler_driver_id, 0);70337034driver_id = (*sampler_driver_id).id;7035} break;7036case DRIVER_RESOURCE_UNIFORM_SET: {7037UniformSet *uniform_set = uniform_set_owner.get_or_null(p_rid);7038ERR_FAIL_NULL_V(uniform_set, 0);70397040driver_id = uniform_set->driver_id.id;7041} break;7042case DRIVER_RESOURCE_BUFFER: {7043Buffer *buffer = nullptr;7044if (vertex_buffer_owner.owns(p_rid)) {7045buffer = vertex_buffer_owner.get_or_null(p_rid);7046} else if (index_buffer_owner.owns(p_rid)) {7047buffer = index_buffer_owner.get_or_null(p_rid);7048} else if (uniform_buffer_owner.owns(p_rid)) {7049buffer = uniform_buffer_owner.get_or_null(p_rid);7050} else if (texture_buffer_owner.owns(p_rid)) {7051buffer = texture_buffer_owner.get_or_null(p_rid);7052} else if (storage_buffer_owner.owns(p_rid)) {7053buffer = storage_buffer_owner.get_or_null(p_rid);7054}7055ERR_FAIL_NULL_V(buffer, 0);70567057driver_id = buffer->driver_id.id;7058} break;7059case DRIVER_RESOURCE_COMPUTE_PIPELINE: {7060ComputePipeline *compute_pipeline = compute_pipeline_owner.get_or_null(p_rid);7061ERR_FAIL_NULL_V(compute_pipeline, 0);70627063driver_id = compute_pipeline->driver_id.id;7064} break;7065case DRIVER_RESOURCE_RENDER_PIPELINE: {7066RenderPipeline *render_pipeline = render_pipeline_owner.get_or_null(p_rid);7067ERR_FAIL_NULL_V(render_pipeline, 0);70687069driver_id = render_pipeline->driver_id.id;7070} break;7071default: {7072ERR_FAIL_V(0);7073} break;7074}70757076return driver->get_resource_native_handle(p_resource, driver_id);7077}70787079String RenderingDevice::get_driver_and_device_memory_report() const {7080return context->get_driver_and_device_memory_report();7081}70827083String RenderingDevice::get_tracked_object_name(uint32_t p_type_index) const {7084return context->get_tracked_object_name(p_type_index);7085}70867087uint64_t RenderingDevice::get_tracked_object_type_count() const {7088return context->get_tracked_object_type_count();7089}70907091uint64_t RenderingDevice::get_driver_total_memory() const {7092return context->get_driver_total_memory();7093}70947095uint64_t RenderingDevice::get_driver_allocation_count() const {7096return context->get_driver_allocation_count();7097}70987099uint64_t RenderingDevice::get_driver_memory_by_object_type(uint32_t p_type) const {7100return context->get_driver_memory_by_object_type(p_type);7101}71027103uint64_t RenderingDevice::get_driver_allocs_by_object_type(uint32_t p_type) const {7104return context->get_driver_allocs_by_object_type(p_type);7105}71067107uint64_t RenderingDevice::get_device_total_memory() const {7108return context->get_device_total_memory();7109}71107111uint64_t RenderingDevice::get_device_allocation_count() const {7112return context->get_device_allocation_count();7113}71147115uint64_t RenderingDevice::get_device_memory_by_object_type(uint32_t type) const {7116return context->get_device_memory_by_object_type(type);7117}71187119uint64_t RenderingDevice::get_device_allocs_by_object_type(uint32_t type) const {7120return context->get_device_allocs_by_object_type(type);7121}71227123uint32_t RenderingDevice::get_captured_timestamps_count() const {7124ERR_RENDER_THREAD_GUARD_V(0);7125return frames[frame].timestamp_result_count;7126}71277128uint64_t RenderingDevice::get_captured_timestamps_frame() const {7129ERR_RENDER_THREAD_GUARD_V(0);7130return frames[frame].index;7131}71327133uint64_t RenderingDevice::get_captured_timestamp_gpu_time(uint32_t p_index) const {7134ERR_RENDER_THREAD_GUARD_V(0);7135ERR_FAIL_UNSIGNED_INDEX_V(p_index, frames[frame].timestamp_result_count, 0);7136return driver->timestamp_query_result_to_time(frames[frame].timestamp_result_values[p_index]);7137}71387139uint64_t RenderingDevice::get_captured_timestamp_cpu_time(uint32_t p_index) const {7140ERR_RENDER_THREAD_GUARD_V(0);7141ERR_FAIL_UNSIGNED_INDEX_V(p_index, frames[frame].timestamp_result_count, 0);7142return frames[frame].timestamp_cpu_result_values[p_index];7143}71447145String RenderingDevice::get_captured_timestamp_name(uint32_t p_index) const {7146ERR_FAIL_UNSIGNED_INDEX_V(p_index, frames[frame].timestamp_result_count, String());7147return frames[frame].timestamp_result_names[p_index];7148}71497150uint64_t RenderingDevice::limit_get(Limit p_limit) const {7151return driver->limit_get(p_limit);7152}71537154void RenderingDevice::finalize() {7155ERR_RENDER_THREAD_GUARD();71567157if (!frames.is_empty()) {7158// Wait for all frames to have finished rendering.7159_flush_and_stall_for_all_frames();7160}71617162// Wait for transfer workers to finish.7163_submit_transfer_workers();7164_wait_for_transfer_workers();71657166// Delete everything the graph has created.7167draw_graph.finalize();71687169// Free all resources.7170_free_rids(render_pipeline_owner, "Pipeline");7171_free_rids(compute_pipeline_owner, "Compute");7172_free_rids(uniform_set_owner, "UniformSet");7173_free_rids(texture_buffer_owner, "TextureBuffer");7174_free_rids(storage_buffer_owner, "StorageBuffer");7175_free_rids(uniform_buffer_owner, "UniformBuffer");7176_free_rids(shader_owner, "Shader");7177_free_rids(index_array_owner, "IndexArray");7178_free_rids(index_buffer_owner, "IndexBuffer");7179_free_rids(vertex_array_owner, "VertexArray");7180_free_rids(vertex_buffer_owner, "VertexBuffer");7181_free_rids(framebuffer_owner, "Framebuffer");7182_free_rids(sampler_owner, "Sampler");7183{7184// For textures it's a bit more difficult because they may be shared.7185LocalVector<RID> owned = texture_owner.get_owned_list();7186if (owned.size()) {7187if (owned.size() == 1) {7188WARN_PRINT("1 RID of type \"Texture\" was leaked.");7189} else {7190WARN_PRINT(vformat("%d RIDs of type \"Texture\" were leaked.", owned.size()));7191}7192LocalVector<RID> owned_non_shared;7193// Free shared first.7194for (const RID &texture_rid : owned) {7195if (texture_is_shared(texture_rid)) {7196#ifdef DEV_ENABLED7197if (resource_names.has(texture_rid)) {7198print_line(String(" - ") + resource_names[texture_rid]);7199}7200#endif7201free(texture_rid);7202} else {7203owned_non_shared.push_back(texture_rid);7204}7205}7206// Free non shared second, this will avoid an error trying to free unexisting textures due to dependencies.7207for (const RID &texture_rid : owned_non_shared) {7208#ifdef DEV_ENABLED7209if (resource_names.has(texture_rid)) {7210print_line(String(" - ") + resource_names[texture_rid]);7211}7212#endif7213free(texture_rid);7214}7215}7216}72177218// Erase the transfer workers after all resources have been freed.7219_free_transfer_workers();72207221// Free everything pending.7222for (uint32_t i = 0; i < frames.size(); i++) {7223int f = (frame + i) % frames.size();7224_free_pending_resources(f);7225driver->command_pool_free(frames[i].command_pool);7226driver->timestamp_query_pool_free(frames[i].timestamp_pool);7227driver->semaphore_free(frames[i].semaphore);7228driver->fence_free(frames[i].fence);72297230RDG::CommandBufferPool &buffer_pool = frames[i].command_buffer_pool;7231for (uint32_t j = 0; j < buffer_pool.buffers.size(); j++) {7232driver->semaphore_free(buffer_pool.semaphores[j]);7233}72347235for (uint32_t j = 0; j < frames[i].transfer_worker_semaphores.size(); j++) {7236driver->semaphore_free(frames[i].transfer_worker_semaphores[j]);7237}7238}72397240if (pipeline_cache_enabled) {7241_update_pipeline_cache(true);7242driver->pipeline_cache_free();7243}72447245frames.clear();72467247for (int i = 0; i < upload_staging_buffers.blocks.size(); i++) {7248driver->buffer_free(upload_staging_buffers.blocks[i].driver_id);7249}72507251for (int i = 0; i < download_staging_buffers.blocks.size(); i++) {7252driver->buffer_free(download_staging_buffers.blocks[i].driver_id);7253}72547255while (vertex_formats.size()) {7256HashMap<VertexFormatID, VertexDescriptionCache>::Iterator temp = vertex_formats.begin();7257driver->vertex_format_free(temp->value.driver_id);7258vertex_formats.remove(temp);7259}72607261for (KeyValue<FramebufferFormatID, FramebufferFormat> &E : framebuffer_formats) {7262driver->render_pass_free(E.value.render_pass);7263}7264framebuffer_formats.clear();72657266// Delete the swap chains created for the screens.7267for (const KeyValue<DisplayServer::WindowID, RDD::SwapChainID> &it : screen_swap_chains) {7268driver->swap_chain_free(it.value);7269}72707271screen_swap_chains.clear();72727273// Delete the command queues.7274if (present_queue) {7275if (main_queue != present_queue) {7276// Only delete the present queue if it's unique.7277driver->command_queue_free(present_queue);7278}72797280present_queue = RDD::CommandQueueID();7281}72827283if (transfer_queue) {7284if (main_queue != transfer_queue) {7285// Only delete the transfer queue if it's unique.7286driver->command_queue_free(transfer_queue);7287}72887289transfer_queue = RDD::CommandQueueID();7290}72917292if (main_queue) {7293driver->command_queue_free(main_queue);7294main_queue = RDD::CommandQueueID();7295}72967297// Delete the driver once everything else has been deleted.7298if (driver != nullptr) {7299context->driver_free(driver);7300driver = nullptr;7301}73027303// All these should be clear at this point.7304ERR_FAIL_COND(dependency_map.size());7305ERR_FAIL_COND(reverse_dependency_map.size());7306}73077308void RenderingDevice::_set_max_fps(int p_max_fps) {7309for (const KeyValue<DisplayServer::WindowID, RDD::SwapChainID> &it : screen_swap_chains) {7310driver->swap_chain_set_max_fps(it.value, p_max_fps);7311}7312}73137314RenderingDevice *RenderingDevice::create_local_device() {7315RenderingDevice *rd = memnew(RenderingDevice);7316if (rd->initialize(context) != OK) {7317memdelete(rd);7318return nullptr;7319}7320return rd;7321}73227323bool RenderingDevice::has_feature(const Features p_feature) const {7324// Some features can be deduced from the capabilities without querying the driver and looking at the capabilities.7325switch (p_feature) {7326case SUPPORTS_MULTIVIEW: {7327const RDD::MultiviewCapabilities &multiview_capabilities = driver->get_multiview_capabilities();7328return multiview_capabilities.is_supported && multiview_capabilities.max_view_count > 1;7329}7330case SUPPORTS_ATTACHMENT_VRS: {7331const RDD::FragmentShadingRateCapabilities &fsr_capabilities = driver->get_fragment_shading_rate_capabilities();7332const RDD::FragmentDensityMapCapabilities &fdm_capabilities = driver->get_fragment_density_map_capabilities();7333return fsr_capabilities.attachment_supported || fdm_capabilities.attachment_supported;7334}7335default:7336return driver->has_feature(p_feature);7337}7338}73397340void RenderingDevice::_bind_methods() {7341ClassDB::bind_method(D_METHOD("texture_create", "format", "view", "data"), &RenderingDevice::_texture_create, DEFVAL(Array()));7342ClassDB::bind_method(D_METHOD("texture_create_shared", "view", "with_texture"), &RenderingDevice::_texture_create_shared);7343ClassDB::bind_method(D_METHOD("texture_create_shared_from_slice", "view", "with_texture", "layer", "mipmap", "mipmaps", "slice_type"), &RenderingDevice::_texture_create_shared_from_slice, DEFVAL(1), DEFVAL(TEXTURE_SLICE_2D));7344ClassDB::bind_method(D_METHOD("texture_create_from_extension", "type", "format", "samples", "usage_flags", "image", "width", "height", "depth", "layers", "mipmaps"), &RenderingDevice::texture_create_from_extension, DEFVAL(1));73457346ClassDB::bind_method(D_METHOD("texture_update", "texture", "layer", "data"), &RenderingDevice::texture_update);7347ClassDB::bind_method(D_METHOD("texture_get_data", "texture", "layer"), &RenderingDevice::texture_get_data);7348ClassDB::bind_method(D_METHOD("texture_get_data_async", "texture", "layer", "callback"), &RenderingDevice::texture_get_data_async);73497350ClassDB::bind_method(D_METHOD("texture_is_format_supported_for_usage", "format", "usage_flags"), &RenderingDevice::texture_is_format_supported_for_usage);73517352ClassDB::bind_method(D_METHOD("texture_is_shared", "texture"), &RenderingDevice::texture_is_shared);7353ClassDB::bind_method(D_METHOD("texture_is_valid", "texture"), &RenderingDevice::texture_is_valid);73547355ClassDB::bind_method(D_METHOD("texture_set_discardable", "texture", "discardable"), &RenderingDevice::texture_set_discardable);7356ClassDB::bind_method(D_METHOD("texture_is_discardable", "texture"), &RenderingDevice::texture_is_discardable);73577358ClassDB::bind_method(D_METHOD("texture_copy", "from_texture", "to_texture", "from_pos", "to_pos", "size", "src_mipmap", "dst_mipmap", "src_layer", "dst_layer"), &RenderingDevice::texture_copy);7359ClassDB::bind_method(D_METHOD("texture_clear", "texture", "color", "base_mipmap", "mipmap_count", "base_layer", "layer_count"), &RenderingDevice::texture_clear);7360ClassDB::bind_method(D_METHOD("texture_resolve_multisample", "from_texture", "to_texture"), &RenderingDevice::texture_resolve_multisample);73617362ClassDB::bind_method(D_METHOD("texture_get_format", "texture"), &RenderingDevice::_texture_get_format);7363#ifndef DISABLE_DEPRECATED7364ClassDB::bind_method(D_METHOD("texture_get_native_handle", "texture"), &RenderingDevice::texture_get_native_handle);7365#endif73667367ClassDB::bind_method(D_METHOD("framebuffer_format_create", "attachments", "view_count"), &RenderingDevice::_framebuffer_format_create, DEFVAL(1));7368ClassDB::bind_method(D_METHOD("framebuffer_format_create_multipass", "attachments", "passes", "view_count"), &RenderingDevice::_framebuffer_format_create_multipass, DEFVAL(1));7369ClassDB::bind_method(D_METHOD("framebuffer_format_create_empty", "samples"), &RenderingDevice::framebuffer_format_create_empty, DEFVAL(TEXTURE_SAMPLES_1));7370ClassDB::bind_method(D_METHOD("framebuffer_format_get_texture_samples", "format", "render_pass"), &RenderingDevice::framebuffer_format_get_texture_samples, DEFVAL(0));7371ClassDB::bind_method(D_METHOD("framebuffer_create", "textures", "validate_with_format", "view_count"), &RenderingDevice::_framebuffer_create, DEFVAL(INVALID_FORMAT_ID), DEFVAL(1));7372ClassDB::bind_method(D_METHOD("framebuffer_create_multipass", "textures", "passes", "validate_with_format", "view_count"), &RenderingDevice::_framebuffer_create_multipass, DEFVAL(INVALID_FORMAT_ID), DEFVAL(1));7373ClassDB::bind_method(D_METHOD("framebuffer_create_empty", "size", "samples", "validate_with_format"), &RenderingDevice::framebuffer_create_empty, DEFVAL(TEXTURE_SAMPLES_1), DEFVAL(INVALID_FORMAT_ID));7374ClassDB::bind_method(D_METHOD("framebuffer_get_format", "framebuffer"), &RenderingDevice::framebuffer_get_format);7375ClassDB::bind_method(D_METHOD("framebuffer_is_valid", "framebuffer"), &RenderingDevice::framebuffer_is_valid);73767377ClassDB::bind_method(D_METHOD("sampler_create", "state"), &RenderingDevice::_sampler_create);7378ClassDB::bind_method(D_METHOD("sampler_is_format_supported_for_filter", "format", "sampler_filter"), &RenderingDevice::sampler_is_format_supported_for_filter);73797380ClassDB::bind_method(D_METHOD("vertex_buffer_create", "size_bytes", "data", "creation_bits"), &RenderingDevice::_vertex_buffer_create, DEFVAL(Vector<uint8_t>()), DEFVAL(0));7381ClassDB::bind_method(D_METHOD("vertex_format_create", "vertex_descriptions"), &RenderingDevice::_vertex_format_create);7382ClassDB::bind_method(D_METHOD("vertex_array_create", "vertex_count", "vertex_format", "src_buffers", "offsets"), &RenderingDevice::_vertex_array_create, DEFVAL(Vector<int64_t>()));73837384ClassDB::bind_method(D_METHOD("index_buffer_create", "size_indices", "format", "data", "use_restart_indices", "creation_bits"), &RenderingDevice::_index_buffer_create, DEFVAL(Vector<uint8_t>()), DEFVAL(false), DEFVAL(0));7385ClassDB::bind_method(D_METHOD("index_array_create", "index_buffer", "index_offset", "index_count"), &RenderingDevice::index_array_create);73867387ClassDB::bind_method(D_METHOD("shader_compile_spirv_from_source", "shader_source", "allow_cache"), &RenderingDevice::_shader_compile_spirv_from_source, DEFVAL(true));7388ClassDB::bind_method(D_METHOD("shader_compile_binary_from_spirv", "spirv_data", "name"), &RenderingDevice::_shader_compile_binary_from_spirv, DEFVAL(""));7389ClassDB::bind_method(D_METHOD("shader_create_from_spirv", "spirv_data", "name"), &RenderingDevice::_shader_create_from_spirv, DEFVAL(""));7390ClassDB::bind_method(D_METHOD("shader_create_from_bytecode", "binary_data", "placeholder_rid"), &RenderingDevice::shader_create_from_bytecode, DEFVAL(RID()));7391ClassDB::bind_method(D_METHOD("shader_create_placeholder"), &RenderingDevice::shader_create_placeholder);73927393ClassDB::bind_method(D_METHOD("shader_get_vertex_input_attribute_mask", "shader"), &RenderingDevice::shader_get_vertex_input_attribute_mask);73947395ClassDB::bind_method(D_METHOD("uniform_buffer_create", "size_bytes", "data", "creation_bits"), &RenderingDevice::_uniform_buffer_create, DEFVAL(Vector<uint8_t>()), DEFVAL(0));7396ClassDB::bind_method(D_METHOD("storage_buffer_create", "size_bytes", "data", "usage", "creation_bits"), &RenderingDevice::_storage_buffer_create, DEFVAL(Vector<uint8_t>()), DEFVAL(0), DEFVAL(0));7397ClassDB::bind_method(D_METHOD("texture_buffer_create", "size_bytes", "format", "data"), &RenderingDevice::_texture_buffer_create, DEFVAL(Vector<uint8_t>()));73987399ClassDB::bind_method(D_METHOD("uniform_set_create", "uniforms", "shader", "shader_set"), &RenderingDevice::_uniform_set_create);7400ClassDB::bind_method(D_METHOD("uniform_set_is_valid", "uniform_set"), &RenderingDevice::uniform_set_is_valid);74017402ClassDB::bind_method(D_METHOD("buffer_copy", "src_buffer", "dst_buffer", "src_offset", "dst_offset", "size"), &RenderingDevice::buffer_copy);7403ClassDB::bind_method(D_METHOD("buffer_update", "buffer", "offset", "size_bytes", "data"), &RenderingDevice::_buffer_update_bind);7404ClassDB::bind_method(D_METHOD("buffer_clear", "buffer", "offset", "size_bytes"), &RenderingDevice::buffer_clear);7405ClassDB::bind_method(D_METHOD("buffer_get_data", "buffer", "offset_bytes", "size_bytes"), &RenderingDevice::buffer_get_data, DEFVAL(0), DEFVAL(0));7406ClassDB::bind_method(D_METHOD("buffer_get_data_async", "buffer", "callback", "offset_bytes", "size_bytes"), &RenderingDevice::buffer_get_data_async, DEFVAL(0), DEFVAL(0));7407ClassDB::bind_method(D_METHOD("buffer_get_device_address", "buffer"), &RenderingDevice::buffer_get_device_address);74087409ClassDB::bind_method(D_METHOD("render_pipeline_create", "shader", "framebuffer_format", "vertex_format", "primitive", "rasterization_state", "multisample_state", "stencil_state", "color_blend_state", "dynamic_state_flags", "for_render_pass", "specialization_constants"), &RenderingDevice::_render_pipeline_create, DEFVAL(0), DEFVAL(0), DEFVAL(TypedArray<RDPipelineSpecializationConstant>()));7410ClassDB::bind_method(D_METHOD("render_pipeline_is_valid", "render_pipeline"), &RenderingDevice::render_pipeline_is_valid);74117412ClassDB::bind_method(D_METHOD("compute_pipeline_create", "shader", "specialization_constants"), &RenderingDevice::_compute_pipeline_create, DEFVAL(TypedArray<RDPipelineSpecializationConstant>()));7413ClassDB::bind_method(D_METHOD("compute_pipeline_is_valid", "compute_pipeline"), &RenderingDevice::compute_pipeline_is_valid);74147415ClassDB::bind_method(D_METHOD("screen_get_width", "screen"), &RenderingDevice::screen_get_width, DEFVAL(DisplayServer::MAIN_WINDOW_ID));7416ClassDB::bind_method(D_METHOD("screen_get_height", "screen"), &RenderingDevice::screen_get_height, DEFVAL(DisplayServer::MAIN_WINDOW_ID));7417ClassDB::bind_method(D_METHOD("screen_get_framebuffer_format", "screen"), &RenderingDevice::screen_get_framebuffer_format, DEFVAL(DisplayServer::MAIN_WINDOW_ID));74187419ClassDB::bind_method(D_METHOD("draw_list_begin_for_screen", "screen", "clear_color"), &RenderingDevice::draw_list_begin_for_screen, DEFVAL(DisplayServer::MAIN_WINDOW_ID), DEFVAL(Color()));74207421ClassDB::bind_method(D_METHOD("draw_list_begin", "framebuffer", "draw_flags", "clear_color_values", "clear_depth_value", "clear_stencil_value", "region", "breadcrumb"), &RenderingDevice::_draw_list_begin_bind, DEFVAL(DRAW_DEFAULT_ALL), DEFVAL(Vector<Color>()), DEFVAL(1.0), DEFVAL(0), DEFVAL(Rect2()), DEFVAL(0));7422#ifndef DISABLE_DEPRECATED7423ClassDB::bind_method(D_METHOD("draw_list_begin_split", "framebuffer", "splits", "initial_color_action", "final_color_action", "initial_depth_action", "final_depth_action", "clear_color_values", "clear_depth", "clear_stencil", "region", "storage_textures"), &RenderingDevice::_draw_list_begin_split, DEFVAL(Vector<Color>()), DEFVAL(1.0), DEFVAL(0), DEFVAL(Rect2()), DEFVAL(TypedArray<RID>()));7424#endif74257426ClassDB::bind_method(D_METHOD("draw_list_set_blend_constants", "draw_list", "color"), &RenderingDevice::draw_list_set_blend_constants);7427ClassDB::bind_method(D_METHOD("draw_list_bind_render_pipeline", "draw_list", "render_pipeline"), &RenderingDevice::draw_list_bind_render_pipeline);7428ClassDB::bind_method(D_METHOD("draw_list_bind_uniform_set", "draw_list", "uniform_set", "set_index"), &RenderingDevice::draw_list_bind_uniform_set);7429ClassDB::bind_method(D_METHOD("draw_list_bind_vertex_array", "draw_list", "vertex_array"), &RenderingDevice::draw_list_bind_vertex_array);7430ClassDB::bind_method(D_METHOD("draw_list_bind_index_array", "draw_list", "index_array"), &RenderingDevice::draw_list_bind_index_array);7431ClassDB::bind_method(D_METHOD("draw_list_set_push_constant", "draw_list", "buffer", "size_bytes"), &RenderingDevice::_draw_list_set_push_constant);74327433ClassDB::bind_method(D_METHOD("draw_list_draw", "draw_list", "use_indices", "instances", "procedural_vertex_count"), &RenderingDevice::draw_list_draw, DEFVAL(0));7434ClassDB::bind_method(D_METHOD("draw_list_draw_indirect", "draw_list", "use_indices", "buffer", "offset", "draw_count", "stride"), &RenderingDevice::draw_list_draw_indirect, DEFVAL(0), DEFVAL(1), DEFVAL(0));74357436ClassDB::bind_method(D_METHOD("draw_list_enable_scissor", "draw_list", "rect"), &RenderingDevice::draw_list_enable_scissor, DEFVAL(Rect2()));7437ClassDB::bind_method(D_METHOD("draw_list_disable_scissor", "draw_list"), &RenderingDevice::draw_list_disable_scissor);74387439ClassDB::bind_method(D_METHOD("draw_list_switch_to_next_pass"), &RenderingDevice::draw_list_switch_to_next_pass);7440#ifndef DISABLE_DEPRECATED7441ClassDB::bind_method(D_METHOD("draw_list_switch_to_next_pass_split", "splits"), &RenderingDevice::_draw_list_switch_to_next_pass_split);7442#endif74437444ClassDB::bind_method(D_METHOD("draw_list_end"), &RenderingDevice::draw_list_end);74457446ClassDB::bind_method(D_METHOD("compute_list_begin"), &RenderingDevice::compute_list_begin);7447ClassDB::bind_method(D_METHOD("compute_list_bind_compute_pipeline", "compute_list", "compute_pipeline"), &RenderingDevice::compute_list_bind_compute_pipeline);7448ClassDB::bind_method(D_METHOD("compute_list_set_push_constant", "compute_list", "buffer", "size_bytes"), &RenderingDevice::_compute_list_set_push_constant);7449ClassDB::bind_method(D_METHOD("compute_list_bind_uniform_set", "compute_list", "uniform_set", "set_index"), &RenderingDevice::compute_list_bind_uniform_set);7450ClassDB::bind_method(D_METHOD("compute_list_dispatch", "compute_list", "x_groups", "y_groups", "z_groups"), &RenderingDevice::compute_list_dispatch);7451ClassDB::bind_method(D_METHOD("compute_list_dispatch_indirect", "compute_list", "buffer", "offset"), &RenderingDevice::compute_list_dispatch_indirect);7452ClassDB::bind_method(D_METHOD("compute_list_add_barrier", "compute_list"), &RenderingDevice::compute_list_add_barrier);7453ClassDB::bind_method(D_METHOD("compute_list_end"), &RenderingDevice::compute_list_end);74547455ClassDB::bind_method(D_METHOD("free_rid", "rid"), &RenderingDevice::free);74567457ClassDB::bind_method(D_METHOD("capture_timestamp", "name"), &RenderingDevice::capture_timestamp);7458ClassDB::bind_method(D_METHOD("get_captured_timestamps_count"), &RenderingDevice::get_captured_timestamps_count);7459ClassDB::bind_method(D_METHOD("get_captured_timestamps_frame"), &RenderingDevice::get_captured_timestamps_frame);7460ClassDB::bind_method(D_METHOD("get_captured_timestamp_gpu_time", "index"), &RenderingDevice::get_captured_timestamp_gpu_time);7461ClassDB::bind_method(D_METHOD("get_captured_timestamp_cpu_time", "index"), &RenderingDevice::get_captured_timestamp_cpu_time);7462ClassDB::bind_method(D_METHOD("get_captured_timestamp_name", "index"), &RenderingDevice::get_captured_timestamp_name);74637464ClassDB::bind_method(D_METHOD("has_feature", "feature"), &RenderingDevice::has_feature);7465ClassDB::bind_method(D_METHOD("limit_get", "limit"), &RenderingDevice::limit_get);7466ClassDB::bind_method(D_METHOD("get_frame_delay"), &RenderingDevice::get_frame_delay);7467ClassDB::bind_method(D_METHOD("submit"), &RenderingDevice::submit);7468ClassDB::bind_method(D_METHOD("sync"), &RenderingDevice::sync);74697470#ifndef DISABLE_DEPRECATED7471ClassDB::bind_method(D_METHOD("barrier", "from", "to"), &RenderingDevice::barrier, DEFVAL(BARRIER_MASK_ALL_BARRIERS), DEFVAL(BARRIER_MASK_ALL_BARRIERS));7472ClassDB::bind_method(D_METHOD("full_barrier"), &RenderingDevice::full_barrier);7473#endif74747475ClassDB::bind_method(D_METHOD("create_local_device"), &RenderingDevice::create_local_device);74767477ClassDB::bind_method(D_METHOD("set_resource_name", "id", "name"), &RenderingDevice::set_resource_name);74787479ClassDB::bind_method(D_METHOD("draw_command_begin_label", "name", "color"), &RenderingDevice::_draw_command_begin_label);7480#ifndef DISABLE_DEPRECATED7481ClassDB::bind_method(D_METHOD("draw_command_insert_label", "name", "color"), &RenderingDevice::draw_command_insert_label);7482#endif7483ClassDB::bind_method(D_METHOD("draw_command_end_label"), &RenderingDevice::draw_command_end_label);74847485ClassDB::bind_method(D_METHOD("get_device_vendor_name"), &RenderingDevice::get_device_vendor_name);7486ClassDB::bind_method(D_METHOD("get_device_name"), &RenderingDevice::get_device_name);7487ClassDB::bind_method(D_METHOD("get_device_pipeline_cache_uuid"), &RenderingDevice::get_device_pipeline_cache_uuid);74887489ClassDB::bind_method(D_METHOD("get_memory_usage", "type"), &RenderingDevice::get_memory_usage);74907491ClassDB::bind_method(D_METHOD("get_driver_resource", "resource", "rid", "index"), &RenderingDevice::get_driver_resource);74927493ClassDB::bind_method(D_METHOD("get_perf_report"), &RenderingDevice::get_perf_report);74947495ClassDB::bind_method(D_METHOD("get_driver_and_device_memory_report"), &RenderingDevice::get_driver_and_device_memory_report);7496ClassDB::bind_method(D_METHOD("get_tracked_object_name", "type_index"), &RenderingDevice::get_tracked_object_name);7497ClassDB::bind_method(D_METHOD("get_tracked_object_type_count"), &RenderingDevice::get_tracked_object_type_count);7498ClassDB::bind_method(D_METHOD("get_driver_total_memory"), &RenderingDevice::get_driver_total_memory);7499ClassDB::bind_method(D_METHOD("get_driver_allocation_count"), &RenderingDevice::get_driver_allocation_count);7500ClassDB::bind_method(D_METHOD("get_driver_memory_by_object_type", "type"), &RenderingDevice::get_driver_memory_by_object_type);7501ClassDB::bind_method(D_METHOD("get_driver_allocs_by_object_type", "type"), &RenderingDevice::get_driver_allocs_by_object_type);7502ClassDB::bind_method(D_METHOD("get_device_total_memory"), &RenderingDevice::get_device_total_memory);7503ClassDB::bind_method(D_METHOD("get_device_allocation_count"), &RenderingDevice::get_device_allocation_count);7504ClassDB::bind_method(D_METHOD("get_device_memory_by_object_type", "type"), &RenderingDevice::get_device_memory_by_object_type);7505ClassDB::bind_method(D_METHOD("get_device_allocs_by_object_type", "type"), &RenderingDevice::get_device_allocs_by_object_type);75067507BIND_ENUM_CONSTANT(DEVICE_TYPE_OTHER);7508BIND_ENUM_CONSTANT(DEVICE_TYPE_INTEGRATED_GPU);7509BIND_ENUM_CONSTANT(DEVICE_TYPE_DISCRETE_GPU);7510BIND_ENUM_CONSTANT(DEVICE_TYPE_VIRTUAL_GPU);7511BIND_ENUM_CONSTANT(DEVICE_TYPE_CPU);7512BIND_ENUM_CONSTANT(DEVICE_TYPE_MAX);75137514BIND_ENUM_CONSTANT(DRIVER_RESOURCE_LOGICAL_DEVICE);7515BIND_ENUM_CONSTANT(DRIVER_RESOURCE_PHYSICAL_DEVICE);7516BIND_ENUM_CONSTANT(DRIVER_RESOURCE_TOPMOST_OBJECT);7517BIND_ENUM_CONSTANT(DRIVER_RESOURCE_COMMAND_QUEUE);7518BIND_ENUM_CONSTANT(DRIVER_RESOURCE_QUEUE_FAMILY);7519BIND_ENUM_CONSTANT(DRIVER_RESOURCE_TEXTURE);7520BIND_ENUM_CONSTANT(DRIVER_RESOURCE_TEXTURE_VIEW);7521BIND_ENUM_CONSTANT(DRIVER_RESOURCE_TEXTURE_DATA_FORMAT);7522BIND_ENUM_CONSTANT(DRIVER_RESOURCE_SAMPLER);7523BIND_ENUM_CONSTANT(DRIVER_RESOURCE_UNIFORM_SET);7524BIND_ENUM_CONSTANT(DRIVER_RESOURCE_BUFFER);7525BIND_ENUM_CONSTANT(DRIVER_RESOURCE_COMPUTE_PIPELINE);7526BIND_ENUM_CONSTANT(DRIVER_RESOURCE_RENDER_PIPELINE);7527#ifndef DISABLE_DEPRECATED7528BIND_ENUM_CONSTANT(DRIVER_RESOURCE_VULKAN_DEVICE);7529BIND_ENUM_CONSTANT(DRIVER_RESOURCE_VULKAN_PHYSICAL_DEVICE);7530BIND_ENUM_CONSTANT(DRIVER_RESOURCE_VULKAN_INSTANCE);7531BIND_ENUM_CONSTANT(DRIVER_RESOURCE_VULKAN_QUEUE);7532BIND_ENUM_CONSTANT(DRIVER_RESOURCE_VULKAN_QUEUE_FAMILY_INDEX);7533BIND_ENUM_CONSTANT(DRIVER_RESOURCE_VULKAN_IMAGE);7534BIND_ENUM_CONSTANT(DRIVER_RESOURCE_VULKAN_IMAGE_VIEW);7535BIND_ENUM_CONSTANT(DRIVER_RESOURCE_VULKAN_IMAGE_NATIVE_TEXTURE_FORMAT);7536BIND_ENUM_CONSTANT(DRIVER_RESOURCE_VULKAN_SAMPLER);7537BIND_ENUM_CONSTANT(DRIVER_RESOURCE_VULKAN_DESCRIPTOR_SET);7538BIND_ENUM_CONSTANT(DRIVER_RESOURCE_VULKAN_BUFFER);7539BIND_ENUM_CONSTANT(DRIVER_RESOURCE_VULKAN_COMPUTE_PIPELINE);7540BIND_ENUM_CONSTANT(DRIVER_RESOURCE_VULKAN_RENDER_PIPELINE);7541#endif75427543BIND_ENUM_CONSTANT(DATA_FORMAT_R4G4_UNORM_PACK8);7544BIND_ENUM_CONSTANT(DATA_FORMAT_R4G4B4A4_UNORM_PACK16);7545BIND_ENUM_CONSTANT(DATA_FORMAT_B4G4R4A4_UNORM_PACK16);7546BIND_ENUM_CONSTANT(DATA_FORMAT_R5G6B5_UNORM_PACK16);7547BIND_ENUM_CONSTANT(DATA_FORMAT_B5G6R5_UNORM_PACK16);7548BIND_ENUM_CONSTANT(DATA_FORMAT_R5G5B5A1_UNORM_PACK16);7549BIND_ENUM_CONSTANT(DATA_FORMAT_B5G5R5A1_UNORM_PACK16);7550BIND_ENUM_CONSTANT(DATA_FORMAT_A1R5G5B5_UNORM_PACK16);7551BIND_ENUM_CONSTANT(DATA_FORMAT_R8_UNORM);7552BIND_ENUM_CONSTANT(DATA_FORMAT_R8_SNORM);7553BIND_ENUM_CONSTANT(DATA_FORMAT_R8_USCALED);7554BIND_ENUM_CONSTANT(DATA_FORMAT_R8_SSCALED);7555BIND_ENUM_CONSTANT(DATA_FORMAT_R8_UINT);7556BIND_ENUM_CONSTANT(DATA_FORMAT_R8_SINT);7557BIND_ENUM_CONSTANT(DATA_FORMAT_R8_SRGB);7558BIND_ENUM_CONSTANT(DATA_FORMAT_R8G8_UNORM);7559BIND_ENUM_CONSTANT(DATA_FORMAT_R8G8_SNORM);7560BIND_ENUM_CONSTANT(DATA_FORMAT_R8G8_USCALED);7561BIND_ENUM_CONSTANT(DATA_FORMAT_R8G8_SSCALED);7562BIND_ENUM_CONSTANT(DATA_FORMAT_R8G8_UINT);7563BIND_ENUM_CONSTANT(DATA_FORMAT_R8G8_SINT);7564BIND_ENUM_CONSTANT(DATA_FORMAT_R8G8_SRGB);7565BIND_ENUM_CONSTANT(DATA_FORMAT_R8G8B8_UNORM);7566BIND_ENUM_CONSTANT(DATA_FORMAT_R8G8B8_SNORM);7567BIND_ENUM_CONSTANT(DATA_FORMAT_R8G8B8_USCALED);7568BIND_ENUM_CONSTANT(DATA_FORMAT_R8G8B8_SSCALED);7569BIND_ENUM_CONSTANT(DATA_FORMAT_R8G8B8_UINT);7570BIND_ENUM_CONSTANT(DATA_FORMAT_R8G8B8_SINT);7571BIND_ENUM_CONSTANT(DATA_FORMAT_R8G8B8_SRGB);7572BIND_ENUM_CONSTANT(DATA_FORMAT_B8G8R8_UNORM);7573BIND_ENUM_CONSTANT(DATA_FORMAT_B8G8R8_SNORM);7574BIND_ENUM_CONSTANT(DATA_FORMAT_B8G8R8_USCALED);7575BIND_ENUM_CONSTANT(DATA_FORMAT_B8G8R8_SSCALED);7576BIND_ENUM_CONSTANT(DATA_FORMAT_B8G8R8_UINT);7577BIND_ENUM_CONSTANT(DATA_FORMAT_B8G8R8_SINT);7578BIND_ENUM_CONSTANT(DATA_FORMAT_B8G8R8_SRGB);7579BIND_ENUM_CONSTANT(DATA_FORMAT_R8G8B8A8_UNORM);7580BIND_ENUM_CONSTANT(DATA_FORMAT_R8G8B8A8_SNORM);7581BIND_ENUM_CONSTANT(DATA_FORMAT_R8G8B8A8_USCALED);7582BIND_ENUM_CONSTANT(DATA_FORMAT_R8G8B8A8_SSCALED);7583BIND_ENUM_CONSTANT(DATA_FORMAT_R8G8B8A8_UINT);7584BIND_ENUM_CONSTANT(DATA_FORMAT_R8G8B8A8_SINT);7585BIND_ENUM_CONSTANT(DATA_FORMAT_R8G8B8A8_SRGB);7586BIND_ENUM_CONSTANT(DATA_FORMAT_B8G8R8A8_UNORM);7587BIND_ENUM_CONSTANT(DATA_FORMAT_B8G8R8A8_SNORM);7588BIND_ENUM_CONSTANT(DATA_FORMAT_B8G8R8A8_USCALED);7589BIND_ENUM_CONSTANT(DATA_FORMAT_B8G8R8A8_SSCALED);7590BIND_ENUM_CONSTANT(DATA_FORMAT_B8G8R8A8_UINT);7591BIND_ENUM_CONSTANT(DATA_FORMAT_B8G8R8A8_SINT);7592BIND_ENUM_CONSTANT(DATA_FORMAT_B8G8R8A8_SRGB);7593BIND_ENUM_CONSTANT(DATA_FORMAT_A8B8G8R8_UNORM_PACK32);7594BIND_ENUM_CONSTANT(DATA_FORMAT_A8B8G8R8_SNORM_PACK32);7595BIND_ENUM_CONSTANT(DATA_FORMAT_A8B8G8R8_USCALED_PACK32);7596BIND_ENUM_CONSTANT(DATA_FORMAT_A8B8G8R8_SSCALED_PACK32);7597BIND_ENUM_CONSTANT(DATA_FORMAT_A8B8G8R8_UINT_PACK32);7598BIND_ENUM_CONSTANT(DATA_FORMAT_A8B8G8R8_SINT_PACK32);7599BIND_ENUM_CONSTANT(DATA_FORMAT_A8B8G8R8_SRGB_PACK32);7600BIND_ENUM_CONSTANT(DATA_FORMAT_A2R10G10B10_UNORM_PACK32);7601BIND_ENUM_CONSTANT(DATA_FORMAT_A2R10G10B10_SNORM_PACK32);7602BIND_ENUM_CONSTANT(DATA_FORMAT_A2R10G10B10_USCALED_PACK32);7603BIND_ENUM_CONSTANT(DATA_FORMAT_A2R10G10B10_SSCALED_PACK32);7604BIND_ENUM_CONSTANT(DATA_FORMAT_A2R10G10B10_UINT_PACK32);7605BIND_ENUM_CONSTANT(DATA_FORMAT_A2R10G10B10_SINT_PACK32);7606BIND_ENUM_CONSTANT(DATA_FORMAT_A2B10G10R10_UNORM_PACK32);7607BIND_ENUM_CONSTANT(DATA_FORMAT_A2B10G10R10_SNORM_PACK32);7608BIND_ENUM_CONSTANT(DATA_FORMAT_A2B10G10R10_USCALED_PACK32);7609BIND_ENUM_CONSTANT(DATA_FORMAT_A2B10G10R10_SSCALED_PACK32);7610BIND_ENUM_CONSTANT(DATA_FORMAT_A2B10G10R10_UINT_PACK32);7611BIND_ENUM_CONSTANT(DATA_FORMAT_A2B10G10R10_SINT_PACK32);7612BIND_ENUM_CONSTANT(DATA_FORMAT_R16_UNORM);7613BIND_ENUM_CONSTANT(DATA_FORMAT_R16_SNORM);7614BIND_ENUM_CONSTANT(DATA_FORMAT_R16_USCALED);7615BIND_ENUM_CONSTANT(DATA_FORMAT_R16_SSCALED);7616BIND_ENUM_CONSTANT(DATA_FORMAT_R16_UINT);7617BIND_ENUM_CONSTANT(DATA_FORMAT_R16_SINT);7618BIND_ENUM_CONSTANT(DATA_FORMAT_R16_SFLOAT);7619BIND_ENUM_CONSTANT(DATA_FORMAT_R16G16_UNORM);7620BIND_ENUM_CONSTANT(DATA_FORMAT_R16G16_SNORM);7621BIND_ENUM_CONSTANT(DATA_FORMAT_R16G16_USCALED);7622BIND_ENUM_CONSTANT(DATA_FORMAT_R16G16_SSCALED);7623BIND_ENUM_CONSTANT(DATA_FORMAT_R16G16_UINT);7624BIND_ENUM_CONSTANT(DATA_FORMAT_R16G16_SINT);7625BIND_ENUM_CONSTANT(DATA_FORMAT_R16G16_SFLOAT);7626BIND_ENUM_CONSTANT(DATA_FORMAT_R16G16B16_UNORM);7627BIND_ENUM_CONSTANT(DATA_FORMAT_R16G16B16_SNORM);7628BIND_ENUM_CONSTANT(DATA_FORMAT_R16G16B16_USCALED);7629BIND_ENUM_CONSTANT(DATA_FORMAT_R16G16B16_SSCALED);7630BIND_ENUM_CONSTANT(DATA_FORMAT_R16G16B16_UINT);7631BIND_ENUM_CONSTANT(DATA_FORMAT_R16G16B16_SINT);7632BIND_ENUM_CONSTANT(DATA_FORMAT_R16G16B16_SFLOAT);7633BIND_ENUM_CONSTANT(DATA_FORMAT_R16G16B16A16_UNORM);7634BIND_ENUM_CONSTANT(DATA_FORMAT_R16G16B16A16_SNORM);7635BIND_ENUM_CONSTANT(DATA_FORMAT_R16G16B16A16_USCALED);7636BIND_ENUM_CONSTANT(DATA_FORMAT_R16G16B16A16_SSCALED);7637BIND_ENUM_CONSTANT(DATA_FORMAT_R16G16B16A16_UINT);7638BIND_ENUM_CONSTANT(DATA_FORMAT_R16G16B16A16_SINT);7639BIND_ENUM_CONSTANT(DATA_FORMAT_R16G16B16A16_SFLOAT);7640BIND_ENUM_CONSTANT(DATA_FORMAT_R32_UINT);7641BIND_ENUM_CONSTANT(DATA_FORMAT_R32_SINT);7642BIND_ENUM_CONSTANT(DATA_FORMAT_R32_SFLOAT);7643BIND_ENUM_CONSTANT(DATA_FORMAT_R32G32_UINT);7644BIND_ENUM_CONSTANT(DATA_FORMAT_R32G32_SINT);7645BIND_ENUM_CONSTANT(DATA_FORMAT_R32G32_SFLOAT);7646BIND_ENUM_CONSTANT(DATA_FORMAT_R32G32B32_UINT);7647BIND_ENUM_CONSTANT(DATA_FORMAT_R32G32B32_SINT);7648BIND_ENUM_CONSTANT(DATA_FORMAT_R32G32B32_SFLOAT);7649BIND_ENUM_CONSTANT(DATA_FORMAT_R32G32B32A32_UINT);7650BIND_ENUM_CONSTANT(DATA_FORMAT_R32G32B32A32_SINT);7651BIND_ENUM_CONSTANT(DATA_FORMAT_R32G32B32A32_SFLOAT);7652BIND_ENUM_CONSTANT(DATA_FORMAT_R64_UINT);7653BIND_ENUM_CONSTANT(DATA_FORMAT_R64_SINT);7654BIND_ENUM_CONSTANT(DATA_FORMAT_R64_SFLOAT);7655BIND_ENUM_CONSTANT(DATA_FORMAT_R64G64_UINT);7656BIND_ENUM_CONSTANT(DATA_FORMAT_R64G64_SINT);7657BIND_ENUM_CONSTANT(DATA_FORMAT_R64G64_SFLOAT);7658BIND_ENUM_CONSTANT(DATA_FORMAT_R64G64B64_UINT);7659BIND_ENUM_CONSTANT(DATA_FORMAT_R64G64B64_SINT);7660BIND_ENUM_CONSTANT(DATA_FORMAT_R64G64B64_SFLOAT);7661BIND_ENUM_CONSTANT(DATA_FORMAT_R64G64B64A64_UINT);7662BIND_ENUM_CONSTANT(DATA_FORMAT_R64G64B64A64_SINT);7663BIND_ENUM_CONSTANT(DATA_FORMAT_R64G64B64A64_SFLOAT);7664BIND_ENUM_CONSTANT(DATA_FORMAT_B10G11R11_UFLOAT_PACK32);7665BIND_ENUM_CONSTANT(DATA_FORMAT_E5B9G9R9_UFLOAT_PACK32);7666BIND_ENUM_CONSTANT(DATA_FORMAT_D16_UNORM);7667BIND_ENUM_CONSTANT(DATA_FORMAT_X8_D24_UNORM_PACK32);7668BIND_ENUM_CONSTANT(DATA_FORMAT_D32_SFLOAT);7669BIND_ENUM_CONSTANT(DATA_FORMAT_S8_UINT);7670BIND_ENUM_CONSTANT(DATA_FORMAT_D16_UNORM_S8_UINT);7671BIND_ENUM_CONSTANT(DATA_FORMAT_D24_UNORM_S8_UINT);7672BIND_ENUM_CONSTANT(DATA_FORMAT_D32_SFLOAT_S8_UINT);7673BIND_ENUM_CONSTANT(DATA_FORMAT_BC1_RGB_UNORM_BLOCK);7674BIND_ENUM_CONSTANT(DATA_FORMAT_BC1_RGB_SRGB_BLOCK);7675BIND_ENUM_CONSTANT(DATA_FORMAT_BC1_RGBA_UNORM_BLOCK);7676BIND_ENUM_CONSTANT(DATA_FORMAT_BC1_RGBA_SRGB_BLOCK);7677BIND_ENUM_CONSTANT(DATA_FORMAT_BC2_UNORM_BLOCK);7678BIND_ENUM_CONSTANT(DATA_FORMAT_BC2_SRGB_BLOCK);7679BIND_ENUM_CONSTANT(DATA_FORMAT_BC3_UNORM_BLOCK);7680BIND_ENUM_CONSTANT(DATA_FORMAT_BC3_SRGB_BLOCK);7681BIND_ENUM_CONSTANT(DATA_FORMAT_BC4_UNORM_BLOCK);7682BIND_ENUM_CONSTANT(DATA_FORMAT_BC4_SNORM_BLOCK);7683BIND_ENUM_CONSTANT(DATA_FORMAT_BC5_UNORM_BLOCK);7684BIND_ENUM_CONSTANT(DATA_FORMAT_BC5_SNORM_BLOCK);7685BIND_ENUM_CONSTANT(DATA_FORMAT_BC6H_UFLOAT_BLOCK);7686BIND_ENUM_CONSTANT(DATA_FORMAT_BC6H_SFLOAT_BLOCK);7687BIND_ENUM_CONSTANT(DATA_FORMAT_BC7_UNORM_BLOCK);7688BIND_ENUM_CONSTANT(DATA_FORMAT_BC7_SRGB_BLOCK);7689BIND_ENUM_CONSTANT(DATA_FORMAT_ETC2_R8G8B8_UNORM_BLOCK);7690BIND_ENUM_CONSTANT(DATA_FORMAT_ETC2_R8G8B8_SRGB_BLOCK);7691BIND_ENUM_CONSTANT(DATA_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK);7692BIND_ENUM_CONSTANT(DATA_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK);7693BIND_ENUM_CONSTANT(DATA_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK);7694BIND_ENUM_CONSTANT(DATA_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK);7695BIND_ENUM_CONSTANT(DATA_FORMAT_EAC_R11_UNORM_BLOCK);7696BIND_ENUM_CONSTANT(DATA_FORMAT_EAC_R11_SNORM_BLOCK);7697BIND_ENUM_CONSTANT(DATA_FORMAT_EAC_R11G11_UNORM_BLOCK);7698BIND_ENUM_CONSTANT(DATA_FORMAT_EAC_R11G11_SNORM_BLOCK);7699BIND_ENUM_CONSTANT(DATA_FORMAT_ASTC_4x4_UNORM_BLOCK);7700BIND_ENUM_CONSTANT(DATA_FORMAT_ASTC_4x4_SRGB_BLOCK);7701BIND_ENUM_CONSTANT(DATA_FORMAT_ASTC_5x4_UNORM_BLOCK);7702BIND_ENUM_CONSTANT(DATA_FORMAT_ASTC_5x4_SRGB_BLOCK);7703BIND_ENUM_CONSTANT(DATA_FORMAT_ASTC_5x5_UNORM_BLOCK);7704BIND_ENUM_CONSTANT(DATA_FORMAT_ASTC_5x5_SRGB_BLOCK);7705BIND_ENUM_CONSTANT(DATA_FORMAT_ASTC_6x5_UNORM_BLOCK);7706BIND_ENUM_CONSTANT(DATA_FORMAT_ASTC_6x5_SRGB_BLOCK);7707BIND_ENUM_CONSTANT(DATA_FORMAT_ASTC_6x6_UNORM_BLOCK);7708BIND_ENUM_CONSTANT(DATA_FORMAT_ASTC_6x6_SRGB_BLOCK);7709BIND_ENUM_CONSTANT(DATA_FORMAT_ASTC_8x5_UNORM_BLOCK);7710BIND_ENUM_CONSTANT(DATA_FORMAT_ASTC_8x5_SRGB_BLOCK);7711BIND_ENUM_CONSTANT(DATA_FORMAT_ASTC_8x6_UNORM_BLOCK);7712BIND_ENUM_CONSTANT(DATA_FORMAT_ASTC_8x6_SRGB_BLOCK);7713BIND_ENUM_CONSTANT(DATA_FORMAT_ASTC_8x8_UNORM_BLOCK);7714BIND_ENUM_CONSTANT(DATA_FORMAT_ASTC_8x8_SRGB_BLOCK);7715BIND_ENUM_CONSTANT(DATA_FORMAT_ASTC_10x5_UNORM_BLOCK);7716BIND_ENUM_CONSTANT(DATA_FORMAT_ASTC_10x5_SRGB_BLOCK);7717BIND_ENUM_CONSTANT(DATA_FORMAT_ASTC_10x6_UNORM_BLOCK);7718BIND_ENUM_CONSTANT(DATA_FORMAT_ASTC_10x6_SRGB_BLOCK);7719BIND_ENUM_CONSTANT(DATA_FORMAT_ASTC_10x8_UNORM_BLOCK);7720BIND_ENUM_CONSTANT(DATA_FORMAT_ASTC_10x8_SRGB_BLOCK);7721BIND_ENUM_CONSTANT(DATA_FORMAT_ASTC_10x10_UNORM_BLOCK);7722BIND_ENUM_CONSTANT(DATA_FORMAT_ASTC_10x10_SRGB_BLOCK);7723BIND_ENUM_CONSTANT(DATA_FORMAT_ASTC_12x10_UNORM_BLOCK);7724BIND_ENUM_CONSTANT(DATA_FORMAT_ASTC_12x10_SRGB_BLOCK);7725BIND_ENUM_CONSTANT(DATA_FORMAT_ASTC_12x12_UNORM_BLOCK);7726BIND_ENUM_CONSTANT(DATA_FORMAT_ASTC_12x12_SRGB_BLOCK);7727BIND_ENUM_CONSTANT(DATA_FORMAT_G8B8G8R8_422_UNORM);7728BIND_ENUM_CONSTANT(DATA_FORMAT_B8G8R8G8_422_UNORM);7729BIND_ENUM_CONSTANT(DATA_FORMAT_G8_B8_R8_3PLANE_420_UNORM);7730BIND_ENUM_CONSTANT(DATA_FORMAT_G8_B8R8_2PLANE_420_UNORM);7731BIND_ENUM_CONSTANT(DATA_FORMAT_G8_B8_R8_3PLANE_422_UNORM);7732BIND_ENUM_CONSTANT(DATA_FORMAT_G8_B8R8_2PLANE_422_UNORM);7733BIND_ENUM_CONSTANT(DATA_FORMAT_G8_B8_R8_3PLANE_444_UNORM);7734BIND_ENUM_CONSTANT(DATA_FORMAT_R10X6_UNORM_PACK16);7735BIND_ENUM_CONSTANT(DATA_FORMAT_R10X6G10X6_UNORM_2PACK16);7736BIND_ENUM_CONSTANT(DATA_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16);7737BIND_ENUM_CONSTANT(DATA_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16);7738BIND_ENUM_CONSTANT(DATA_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16);7739BIND_ENUM_CONSTANT(DATA_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16);7740BIND_ENUM_CONSTANT(DATA_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16);7741BIND_ENUM_CONSTANT(DATA_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16);7742BIND_ENUM_CONSTANT(DATA_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16);7743BIND_ENUM_CONSTANT(DATA_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16);7744BIND_ENUM_CONSTANT(DATA_FORMAT_R12X4_UNORM_PACK16);7745BIND_ENUM_CONSTANT(DATA_FORMAT_R12X4G12X4_UNORM_2PACK16);7746BIND_ENUM_CONSTANT(DATA_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16);7747BIND_ENUM_CONSTANT(DATA_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16);7748BIND_ENUM_CONSTANT(DATA_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16);7749BIND_ENUM_CONSTANT(DATA_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16);7750BIND_ENUM_CONSTANT(DATA_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16);7751BIND_ENUM_CONSTANT(DATA_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16);7752BIND_ENUM_CONSTANT(DATA_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16);7753BIND_ENUM_CONSTANT(DATA_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16);7754BIND_ENUM_CONSTANT(DATA_FORMAT_G16B16G16R16_422_UNORM);7755BIND_ENUM_CONSTANT(DATA_FORMAT_B16G16R16G16_422_UNORM);7756BIND_ENUM_CONSTANT(DATA_FORMAT_G16_B16_R16_3PLANE_420_UNORM);7757BIND_ENUM_CONSTANT(DATA_FORMAT_G16_B16R16_2PLANE_420_UNORM);7758BIND_ENUM_CONSTANT(DATA_FORMAT_G16_B16_R16_3PLANE_422_UNORM);7759BIND_ENUM_CONSTANT(DATA_FORMAT_G16_B16R16_2PLANE_422_UNORM);7760BIND_ENUM_CONSTANT(DATA_FORMAT_G16_B16_R16_3PLANE_444_UNORM);7761BIND_ENUM_CONSTANT(DATA_FORMAT_ASTC_4x4_SFLOAT_BLOCK);7762BIND_ENUM_CONSTANT(DATA_FORMAT_ASTC_5x4_SFLOAT_BLOCK);7763BIND_ENUM_CONSTANT(DATA_FORMAT_ASTC_5x5_SFLOAT_BLOCK);7764BIND_ENUM_CONSTANT(DATA_FORMAT_ASTC_6x5_SFLOAT_BLOCK);7765BIND_ENUM_CONSTANT(DATA_FORMAT_ASTC_6x6_SFLOAT_BLOCK);7766BIND_ENUM_CONSTANT(DATA_FORMAT_ASTC_8x5_SFLOAT_BLOCK);7767BIND_ENUM_CONSTANT(DATA_FORMAT_ASTC_8x6_SFLOAT_BLOCK);7768BIND_ENUM_CONSTANT(DATA_FORMAT_ASTC_8x8_SFLOAT_BLOCK);7769BIND_ENUM_CONSTANT(DATA_FORMAT_ASTC_10x5_SFLOAT_BLOCK);7770BIND_ENUM_CONSTANT(DATA_FORMAT_ASTC_10x6_SFLOAT_BLOCK);7771BIND_ENUM_CONSTANT(DATA_FORMAT_ASTC_10x8_SFLOAT_BLOCK);7772BIND_ENUM_CONSTANT(DATA_FORMAT_ASTC_10x10_SFLOAT_BLOCK);7773BIND_ENUM_CONSTANT(DATA_FORMAT_ASTC_12x10_SFLOAT_BLOCK);7774BIND_ENUM_CONSTANT(DATA_FORMAT_ASTC_12x12_SFLOAT_BLOCK);7775BIND_ENUM_CONSTANT(DATA_FORMAT_MAX);77767777#ifndef DISABLE_DEPRECATED7778BIND_BITFIELD_FLAG(BARRIER_MASK_VERTEX);7779BIND_BITFIELD_FLAG(BARRIER_MASK_FRAGMENT);7780BIND_BITFIELD_FLAG(BARRIER_MASK_COMPUTE);7781BIND_BITFIELD_FLAG(BARRIER_MASK_TRANSFER);7782BIND_BITFIELD_FLAG(BARRIER_MASK_RASTER);7783BIND_BITFIELD_FLAG(BARRIER_MASK_ALL_BARRIERS);7784BIND_BITFIELD_FLAG(BARRIER_MASK_NO_BARRIER);7785#endif77867787BIND_ENUM_CONSTANT(TEXTURE_TYPE_1D);7788BIND_ENUM_CONSTANT(TEXTURE_TYPE_2D);7789BIND_ENUM_CONSTANT(TEXTURE_TYPE_3D);7790BIND_ENUM_CONSTANT(TEXTURE_TYPE_CUBE);7791BIND_ENUM_CONSTANT(TEXTURE_TYPE_1D_ARRAY);7792BIND_ENUM_CONSTANT(TEXTURE_TYPE_2D_ARRAY);7793BIND_ENUM_CONSTANT(TEXTURE_TYPE_CUBE_ARRAY);7794BIND_ENUM_CONSTANT(TEXTURE_TYPE_MAX);77957796BIND_ENUM_CONSTANT(TEXTURE_SAMPLES_1);7797BIND_ENUM_CONSTANT(TEXTURE_SAMPLES_2);7798BIND_ENUM_CONSTANT(TEXTURE_SAMPLES_4);7799BIND_ENUM_CONSTANT(TEXTURE_SAMPLES_8);7800BIND_ENUM_CONSTANT(TEXTURE_SAMPLES_16);7801BIND_ENUM_CONSTANT(TEXTURE_SAMPLES_32);7802BIND_ENUM_CONSTANT(TEXTURE_SAMPLES_64);7803BIND_ENUM_CONSTANT(TEXTURE_SAMPLES_MAX);78047805BIND_BITFIELD_FLAG(TEXTURE_USAGE_SAMPLING_BIT);7806BIND_BITFIELD_FLAG(TEXTURE_USAGE_COLOR_ATTACHMENT_BIT);7807BIND_BITFIELD_FLAG(TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT);7808BIND_BITFIELD_FLAG(TEXTURE_USAGE_STORAGE_BIT);7809BIND_BITFIELD_FLAG(TEXTURE_USAGE_STORAGE_ATOMIC_BIT);7810BIND_BITFIELD_FLAG(TEXTURE_USAGE_CPU_READ_BIT);7811BIND_BITFIELD_FLAG(TEXTURE_USAGE_CAN_UPDATE_BIT);7812BIND_BITFIELD_FLAG(TEXTURE_USAGE_CAN_COPY_FROM_BIT);7813BIND_BITFIELD_FLAG(TEXTURE_USAGE_CAN_COPY_TO_BIT);7814BIND_BITFIELD_FLAG(TEXTURE_USAGE_INPUT_ATTACHMENT_BIT);78157816BIND_ENUM_CONSTANT(TEXTURE_SWIZZLE_IDENTITY);7817BIND_ENUM_CONSTANT(TEXTURE_SWIZZLE_ZERO);7818BIND_ENUM_CONSTANT(TEXTURE_SWIZZLE_ONE);7819BIND_ENUM_CONSTANT(TEXTURE_SWIZZLE_R);7820BIND_ENUM_CONSTANT(TEXTURE_SWIZZLE_G);7821BIND_ENUM_CONSTANT(TEXTURE_SWIZZLE_B);7822BIND_ENUM_CONSTANT(TEXTURE_SWIZZLE_A);7823BIND_ENUM_CONSTANT(TEXTURE_SWIZZLE_MAX);78247825BIND_ENUM_CONSTANT(TEXTURE_SLICE_2D);7826BIND_ENUM_CONSTANT(TEXTURE_SLICE_CUBEMAP);7827BIND_ENUM_CONSTANT(TEXTURE_SLICE_3D);78287829BIND_ENUM_CONSTANT(SAMPLER_FILTER_NEAREST);7830BIND_ENUM_CONSTANT(SAMPLER_FILTER_LINEAR);7831BIND_ENUM_CONSTANT(SAMPLER_REPEAT_MODE_REPEAT);7832BIND_ENUM_CONSTANT(SAMPLER_REPEAT_MODE_MIRRORED_REPEAT);7833BIND_ENUM_CONSTANT(SAMPLER_REPEAT_MODE_CLAMP_TO_EDGE);7834BIND_ENUM_CONSTANT(SAMPLER_REPEAT_MODE_CLAMP_TO_BORDER);7835BIND_ENUM_CONSTANT(SAMPLER_REPEAT_MODE_MIRROR_CLAMP_TO_EDGE);7836BIND_ENUM_CONSTANT(SAMPLER_REPEAT_MODE_MAX);78377838BIND_ENUM_CONSTANT(SAMPLER_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK);7839BIND_ENUM_CONSTANT(SAMPLER_BORDER_COLOR_INT_TRANSPARENT_BLACK);7840BIND_ENUM_CONSTANT(SAMPLER_BORDER_COLOR_FLOAT_OPAQUE_BLACK);7841BIND_ENUM_CONSTANT(SAMPLER_BORDER_COLOR_INT_OPAQUE_BLACK);7842BIND_ENUM_CONSTANT(SAMPLER_BORDER_COLOR_FLOAT_OPAQUE_WHITE);7843BIND_ENUM_CONSTANT(SAMPLER_BORDER_COLOR_INT_OPAQUE_WHITE);7844BIND_ENUM_CONSTANT(SAMPLER_BORDER_COLOR_MAX);78457846BIND_ENUM_CONSTANT(VERTEX_FREQUENCY_VERTEX);7847BIND_ENUM_CONSTANT(VERTEX_FREQUENCY_INSTANCE);78487849BIND_ENUM_CONSTANT(INDEX_BUFFER_FORMAT_UINT16);7850BIND_ENUM_CONSTANT(INDEX_BUFFER_FORMAT_UINT32);78517852BIND_BITFIELD_FLAG(STORAGE_BUFFER_USAGE_DISPATCH_INDIRECT);78537854BIND_BITFIELD_FLAG(BUFFER_CREATION_DEVICE_ADDRESS_BIT);7855BIND_BITFIELD_FLAG(BUFFER_CREATION_AS_STORAGE_BIT);78567857BIND_ENUM_CONSTANT(UNIFORM_TYPE_SAMPLER); //for sampling only (sampler GLSL type)7858BIND_ENUM_CONSTANT(UNIFORM_TYPE_SAMPLER_WITH_TEXTURE); // for sampling only); but includes a texture); (samplerXX GLSL type)); first a sampler then a texture7859BIND_ENUM_CONSTANT(UNIFORM_TYPE_TEXTURE); //only texture); (textureXX GLSL type)7860BIND_ENUM_CONSTANT(UNIFORM_TYPE_IMAGE); // storage image (imageXX GLSL type)); for compute mostly7861BIND_ENUM_CONSTANT(UNIFORM_TYPE_TEXTURE_BUFFER); // buffer texture (or TBO); textureBuffer type)7862BIND_ENUM_CONSTANT(UNIFORM_TYPE_SAMPLER_WITH_TEXTURE_BUFFER); // buffer texture with a sampler(or TBO); samplerBuffer type)7863BIND_ENUM_CONSTANT(UNIFORM_TYPE_IMAGE_BUFFER); //texel buffer); (imageBuffer type)); for compute mostly7864BIND_ENUM_CONSTANT(UNIFORM_TYPE_UNIFORM_BUFFER); //regular uniform buffer (or UBO).7865BIND_ENUM_CONSTANT(UNIFORM_TYPE_STORAGE_BUFFER); //storage buffer ("buffer" qualifier) like UBO); but supports storage); for compute mostly7866BIND_ENUM_CONSTANT(UNIFORM_TYPE_INPUT_ATTACHMENT); //used for sub-pass read/write); for mobile mostly7867BIND_ENUM_CONSTANT(UNIFORM_TYPE_MAX);78687869BIND_ENUM_CONSTANT(RENDER_PRIMITIVE_POINTS);7870BIND_ENUM_CONSTANT(RENDER_PRIMITIVE_LINES);7871BIND_ENUM_CONSTANT(RENDER_PRIMITIVE_LINES_WITH_ADJACENCY);7872BIND_ENUM_CONSTANT(RENDER_PRIMITIVE_LINESTRIPS);7873BIND_ENUM_CONSTANT(RENDER_PRIMITIVE_LINESTRIPS_WITH_ADJACENCY);7874BIND_ENUM_CONSTANT(RENDER_PRIMITIVE_TRIANGLES);7875BIND_ENUM_CONSTANT(RENDER_PRIMITIVE_TRIANGLES_WITH_ADJACENCY);7876BIND_ENUM_CONSTANT(RENDER_PRIMITIVE_TRIANGLE_STRIPS);7877BIND_ENUM_CONSTANT(RENDER_PRIMITIVE_TRIANGLE_STRIPS_WITH_AJACENCY);7878BIND_ENUM_CONSTANT(RENDER_PRIMITIVE_TRIANGLE_STRIPS_WITH_RESTART_INDEX);7879BIND_ENUM_CONSTANT(RENDER_PRIMITIVE_TESSELATION_PATCH);7880BIND_ENUM_CONSTANT(RENDER_PRIMITIVE_MAX);78817882BIND_ENUM_CONSTANT(POLYGON_CULL_DISABLED);7883BIND_ENUM_CONSTANT(POLYGON_CULL_FRONT);7884BIND_ENUM_CONSTANT(POLYGON_CULL_BACK);78857886BIND_ENUM_CONSTANT(POLYGON_FRONT_FACE_CLOCKWISE);7887BIND_ENUM_CONSTANT(POLYGON_FRONT_FACE_COUNTER_CLOCKWISE);78887889BIND_ENUM_CONSTANT(STENCIL_OP_KEEP);7890BIND_ENUM_CONSTANT(STENCIL_OP_ZERO);7891BIND_ENUM_CONSTANT(STENCIL_OP_REPLACE);7892BIND_ENUM_CONSTANT(STENCIL_OP_INCREMENT_AND_CLAMP);7893BIND_ENUM_CONSTANT(STENCIL_OP_DECREMENT_AND_CLAMP);7894BIND_ENUM_CONSTANT(STENCIL_OP_INVERT);7895BIND_ENUM_CONSTANT(STENCIL_OP_INCREMENT_AND_WRAP);7896BIND_ENUM_CONSTANT(STENCIL_OP_DECREMENT_AND_WRAP);7897BIND_ENUM_CONSTANT(STENCIL_OP_MAX); //not an actual operator); just the amount of operators :D78987899BIND_ENUM_CONSTANT(COMPARE_OP_NEVER);7900BIND_ENUM_CONSTANT(COMPARE_OP_LESS);7901BIND_ENUM_CONSTANT(COMPARE_OP_EQUAL);7902BIND_ENUM_CONSTANT(COMPARE_OP_LESS_OR_EQUAL);7903BIND_ENUM_CONSTANT(COMPARE_OP_GREATER);7904BIND_ENUM_CONSTANT(COMPARE_OP_NOT_EQUAL);7905BIND_ENUM_CONSTANT(COMPARE_OP_GREATER_OR_EQUAL);7906BIND_ENUM_CONSTANT(COMPARE_OP_ALWAYS);7907BIND_ENUM_CONSTANT(COMPARE_OP_MAX);79087909BIND_ENUM_CONSTANT(LOGIC_OP_CLEAR);7910BIND_ENUM_CONSTANT(LOGIC_OP_AND);7911BIND_ENUM_CONSTANT(LOGIC_OP_AND_REVERSE);7912BIND_ENUM_CONSTANT(LOGIC_OP_COPY);7913BIND_ENUM_CONSTANT(LOGIC_OP_AND_INVERTED);7914BIND_ENUM_CONSTANT(LOGIC_OP_NO_OP);7915BIND_ENUM_CONSTANT(LOGIC_OP_XOR);7916BIND_ENUM_CONSTANT(LOGIC_OP_OR);7917BIND_ENUM_CONSTANT(LOGIC_OP_NOR);7918BIND_ENUM_CONSTANT(LOGIC_OP_EQUIVALENT);7919BIND_ENUM_CONSTANT(LOGIC_OP_INVERT);7920BIND_ENUM_CONSTANT(LOGIC_OP_OR_REVERSE);7921BIND_ENUM_CONSTANT(LOGIC_OP_COPY_INVERTED);7922BIND_ENUM_CONSTANT(LOGIC_OP_OR_INVERTED);7923BIND_ENUM_CONSTANT(LOGIC_OP_NAND);7924BIND_ENUM_CONSTANT(LOGIC_OP_SET);7925BIND_ENUM_CONSTANT(LOGIC_OP_MAX); //not an actual operator); just the amount of operators :D79267927BIND_ENUM_CONSTANT(BLEND_FACTOR_ZERO);7928BIND_ENUM_CONSTANT(BLEND_FACTOR_ONE);7929BIND_ENUM_CONSTANT(BLEND_FACTOR_SRC_COLOR);7930BIND_ENUM_CONSTANT(BLEND_FACTOR_ONE_MINUS_SRC_COLOR);7931BIND_ENUM_CONSTANT(BLEND_FACTOR_DST_COLOR);7932BIND_ENUM_CONSTANT(BLEND_FACTOR_ONE_MINUS_DST_COLOR);7933BIND_ENUM_CONSTANT(BLEND_FACTOR_SRC_ALPHA);7934BIND_ENUM_CONSTANT(BLEND_FACTOR_ONE_MINUS_SRC_ALPHA);7935BIND_ENUM_CONSTANT(BLEND_FACTOR_DST_ALPHA);7936BIND_ENUM_CONSTANT(BLEND_FACTOR_ONE_MINUS_DST_ALPHA);7937BIND_ENUM_CONSTANT(BLEND_FACTOR_CONSTANT_COLOR);7938BIND_ENUM_CONSTANT(BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR);7939BIND_ENUM_CONSTANT(BLEND_FACTOR_CONSTANT_ALPHA);7940BIND_ENUM_CONSTANT(BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA);7941BIND_ENUM_CONSTANT(BLEND_FACTOR_SRC_ALPHA_SATURATE);7942BIND_ENUM_CONSTANT(BLEND_FACTOR_SRC1_COLOR);7943BIND_ENUM_CONSTANT(BLEND_FACTOR_ONE_MINUS_SRC1_COLOR);7944BIND_ENUM_CONSTANT(BLEND_FACTOR_SRC1_ALPHA);7945BIND_ENUM_CONSTANT(BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA);7946BIND_ENUM_CONSTANT(BLEND_FACTOR_MAX);79477948BIND_ENUM_CONSTANT(BLEND_OP_ADD);7949BIND_ENUM_CONSTANT(BLEND_OP_SUBTRACT);7950BIND_ENUM_CONSTANT(BLEND_OP_REVERSE_SUBTRACT);7951BIND_ENUM_CONSTANT(BLEND_OP_MINIMUM);7952BIND_ENUM_CONSTANT(BLEND_OP_MAXIMUM);7953BIND_ENUM_CONSTANT(BLEND_OP_MAX);79547955BIND_BITFIELD_FLAG(DYNAMIC_STATE_LINE_WIDTH);7956BIND_BITFIELD_FLAG(DYNAMIC_STATE_DEPTH_BIAS);7957BIND_BITFIELD_FLAG(DYNAMIC_STATE_BLEND_CONSTANTS);7958BIND_BITFIELD_FLAG(DYNAMIC_STATE_DEPTH_BOUNDS);7959BIND_BITFIELD_FLAG(DYNAMIC_STATE_STENCIL_COMPARE_MASK);7960BIND_BITFIELD_FLAG(DYNAMIC_STATE_STENCIL_WRITE_MASK);7961BIND_BITFIELD_FLAG(DYNAMIC_STATE_STENCIL_REFERENCE);79627963#ifndef DISABLE_DEPRECATED7964BIND_ENUM_CONSTANT(INITIAL_ACTION_LOAD);7965BIND_ENUM_CONSTANT(INITIAL_ACTION_CLEAR);7966BIND_ENUM_CONSTANT(INITIAL_ACTION_DISCARD);7967BIND_ENUM_CONSTANT(INITIAL_ACTION_MAX);7968BIND_ENUM_CONSTANT(INITIAL_ACTION_CLEAR_REGION);7969BIND_ENUM_CONSTANT(INITIAL_ACTION_CLEAR_REGION_CONTINUE);7970BIND_ENUM_CONSTANT(INITIAL_ACTION_KEEP);7971BIND_ENUM_CONSTANT(INITIAL_ACTION_DROP);7972BIND_ENUM_CONSTANT(INITIAL_ACTION_CONTINUE);79737974BIND_ENUM_CONSTANT(FINAL_ACTION_STORE);7975BIND_ENUM_CONSTANT(FINAL_ACTION_DISCARD);7976BIND_ENUM_CONSTANT(FINAL_ACTION_MAX);7977BIND_ENUM_CONSTANT(FINAL_ACTION_READ);7978BIND_ENUM_CONSTANT(FINAL_ACTION_CONTINUE);7979#endif79807981BIND_ENUM_CONSTANT(SHADER_STAGE_VERTEX);7982BIND_ENUM_CONSTANT(SHADER_STAGE_FRAGMENT);7983BIND_ENUM_CONSTANT(SHADER_STAGE_TESSELATION_CONTROL);7984BIND_ENUM_CONSTANT(SHADER_STAGE_TESSELATION_EVALUATION);7985BIND_ENUM_CONSTANT(SHADER_STAGE_COMPUTE);7986BIND_ENUM_CONSTANT(SHADER_STAGE_MAX);7987BIND_ENUM_CONSTANT(SHADER_STAGE_VERTEX_BIT);7988BIND_ENUM_CONSTANT(SHADER_STAGE_FRAGMENT_BIT);7989BIND_ENUM_CONSTANT(SHADER_STAGE_TESSELATION_CONTROL_BIT);7990BIND_ENUM_CONSTANT(SHADER_STAGE_TESSELATION_EVALUATION_BIT);7991BIND_ENUM_CONSTANT(SHADER_STAGE_COMPUTE_BIT);79927993BIND_ENUM_CONSTANT(SHADER_LANGUAGE_GLSL);7994BIND_ENUM_CONSTANT(SHADER_LANGUAGE_HLSL);79957996BIND_ENUM_CONSTANT(PIPELINE_SPECIALIZATION_CONSTANT_TYPE_BOOL);7997BIND_ENUM_CONSTANT(PIPELINE_SPECIALIZATION_CONSTANT_TYPE_INT);7998BIND_ENUM_CONSTANT(PIPELINE_SPECIALIZATION_CONSTANT_TYPE_FLOAT);79998000BIND_ENUM_CONSTANT(SUPPORTS_METALFX_SPATIAL);8001BIND_ENUM_CONSTANT(SUPPORTS_METALFX_TEMPORAL);8002BIND_ENUM_CONSTANT(SUPPORTS_BUFFER_DEVICE_ADDRESS);8003BIND_ENUM_CONSTANT(SUPPORTS_IMAGE_ATOMIC_32_BIT);80048005BIND_ENUM_CONSTANT(LIMIT_MAX_BOUND_UNIFORM_SETS);8006BIND_ENUM_CONSTANT(LIMIT_MAX_FRAMEBUFFER_COLOR_ATTACHMENTS);8007BIND_ENUM_CONSTANT(LIMIT_MAX_TEXTURES_PER_UNIFORM_SET);8008BIND_ENUM_CONSTANT(LIMIT_MAX_SAMPLERS_PER_UNIFORM_SET);8009BIND_ENUM_CONSTANT(LIMIT_MAX_STORAGE_BUFFERS_PER_UNIFORM_SET);8010BIND_ENUM_CONSTANT(LIMIT_MAX_STORAGE_IMAGES_PER_UNIFORM_SET);8011BIND_ENUM_CONSTANT(LIMIT_MAX_UNIFORM_BUFFERS_PER_UNIFORM_SET);8012BIND_ENUM_CONSTANT(LIMIT_MAX_DRAW_INDEXED_INDEX);8013BIND_ENUM_CONSTANT(LIMIT_MAX_FRAMEBUFFER_HEIGHT);8014BIND_ENUM_CONSTANT(LIMIT_MAX_FRAMEBUFFER_WIDTH);8015BIND_ENUM_CONSTANT(LIMIT_MAX_TEXTURE_ARRAY_LAYERS);8016BIND_ENUM_CONSTANT(LIMIT_MAX_TEXTURE_SIZE_1D);8017BIND_ENUM_CONSTANT(LIMIT_MAX_TEXTURE_SIZE_2D);8018BIND_ENUM_CONSTANT(LIMIT_MAX_TEXTURE_SIZE_3D);8019BIND_ENUM_CONSTANT(LIMIT_MAX_TEXTURE_SIZE_CUBE);8020BIND_ENUM_CONSTANT(LIMIT_MAX_TEXTURES_PER_SHADER_STAGE);8021BIND_ENUM_CONSTANT(LIMIT_MAX_SAMPLERS_PER_SHADER_STAGE);8022BIND_ENUM_CONSTANT(LIMIT_MAX_STORAGE_BUFFERS_PER_SHADER_STAGE);8023BIND_ENUM_CONSTANT(LIMIT_MAX_STORAGE_IMAGES_PER_SHADER_STAGE);8024BIND_ENUM_CONSTANT(LIMIT_MAX_UNIFORM_BUFFERS_PER_SHADER_STAGE);8025BIND_ENUM_CONSTANT(LIMIT_MAX_PUSH_CONSTANT_SIZE);8026BIND_ENUM_CONSTANT(LIMIT_MAX_UNIFORM_BUFFER_SIZE);8027BIND_ENUM_CONSTANT(LIMIT_MAX_VERTEX_INPUT_ATTRIBUTE_OFFSET);8028BIND_ENUM_CONSTANT(LIMIT_MAX_VERTEX_INPUT_ATTRIBUTES);8029BIND_ENUM_CONSTANT(LIMIT_MAX_VERTEX_INPUT_BINDINGS);8030BIND_ENUM_CONSTANT(LIMIT_MAX_VERTEX_INPUT_BINDING_STRIDE);8031BIND_ENUM_CONSTANT(LIMIT_MIN_UNIFORM_BUFFER_OFFSET_ALIGNMENT);8032BIND_ENUM_CONSTANT(LIMIT_MAX_COMPUTE_SHARED_MEMORY_SIZE);8033BIND_ENUM_CONSTANT(LIMIT_MAX_COMPUTE_WORKGROUP_COUNT_X);8034BIND_ENUM_CONSTANT(LIMIT_MAX_COMPUTE_WORKGROUP_COUNT_Y);8035BIND_ENUM_CONSTANT(LIMIT_MAX_COMPUTE_WORKGROUP_COUNT_Z);8036BIND_ENUM_CONSTANT(LIMIT_MAX_COMPUTE_WORKGROUP_INVOCATIONS);8037BIND_ENUM_CONSTANT(LIMIT_MAX_COMPUTE_WORKGROUP_SIZE_X);8038BIND_ENUM_CONSTANT(LIMIT_MAX_COMPUTE_WORKGROUP_SIZE_Y);8039BIND_ENUM_CONSTANT(LIMIT_MAX_COMPUTE_WORKGROUP_SIZE_Z);8040BIND_ENUM_CONSTANT(LIMIT_MAX_VIEWPORT_DIMENSIONS_X);8041BIND_ENUM_CONSTANT(LIMIT_MAX_VIEWPORT_DIMENSIONS_Y);8042BIND_ENUM_CONSTANT(LIMIT_METALFX_TEMPORAL_SCALER_MIN_SCALE);8043BIND_ENUM_CONSTANT(LIMIT_METALFX_TEMPORAL_SCALER_MAX_SCALE);80448045BIND_ENUM_CONSTANT(MEMORY_TEXTURES);8046BIND_ENUM_CONSTANT(MEMORY_BUFFERS);8047BIND_ENUM_CONSTANT(MEMORY_TOTAL);80488049BIND_CONSTANT(INVALID_ID);8050BIND_CONSTANT(INVALID_FORMAT_ID);80518052BIND_ENUM_CONSTANT(NONE);8053BIND_ENUM_CONSTANT(REFLECTION_PROBES);8054BIND_ENUM_CONSTANT(SKY_PASS);8055BIND_ENUM_CONSTANT(LIGHTMAPPER_PASS);8056BIND_ENUM_CONSTANT(SHADOW_PASS_DIRECTIONAL);8057BIND_ENUM_CONSTANT(SHADOW_PASS_CUBE);8058BIND_ENUM_CONSTANT(OPAQUE_PASS);8059BIND_ENUM_CONSTANT(ALPHA_PASS);8060BIND_ENUM_CONSTANT(TRANSPARENT_PASS);8061BIND_ENUM_CONSTANT(POST_PROCESSING_PASS);8062BIND_ENUM_CONSTANT(BLIT_PASS);8063BIND_ENUM_CONSTANT(UI_PASS);8064BIND_ENUM_CONSTANT(DEBUG_PASS);80658066BIND_BITFIELD_FLAG(DRAW_DEFAULT_ALL);8067BIND_BITFIELD_FLAG(DRAW_CLEAR_COLOR_0);8068BIND_BITFIELD_FLAG(DRAW_CLEAR_COLOR_1);8069BIND_BITFIELD_FLAG(DRAW_CLEAR_COLOR_2);8070BIND_BITFIELD_FLAG(DRAW_CLEAR_COLOR_3);8071BIND_BITFIELD_FLAG(DRAW_CLEAR_COLOR_4);8072BIND_BITFIELD_FLAG(DRAW_CLEAR_COLOR_5);8073BIND_BITFIELD_FLAG(DRAW_CLEAR_COLOR_6);8074BIND_BITFIELD_FLAG(DRAW_CLEAR_COLOR_7);8075BIND_BITFIELD_FLAG(DRAW_CLEAR_COLOR_MASK);8076BIND_BITFIELD_FLAG(DRAW_CLEAR_COLOR_ALL);8077BIND_BITFIELD_FLAG(DRAW_IGNORE_COLOR_0);8078BIND_BITFIELD_FLAG(DRAW_IGNORE_COLOR_1);8079BIND_BITFIELD_FLAG(DRAW_IGNORE_COLOR_2);8080BIND_BITFIELD_FLAG(DRAW_IGNORE_COLOR_3);8081BIND_BITFIELD_FLAG(DRAW_IGNORE_COLOR_4);8082BIND_BITFIELD_FLAG(DRAW_IGNORE_COLOR_5);8083BIND_BITFIELD_FLAG(DRAW_IGNORE_COLOR_6);8084BIND_BITFIELD_FLAG(DRAW_IGNORE_COLOR_7);8085BIND_BITFIELD_FLAG(DRAW_IGNORE_COLOR_MASK);8086BIND_BITFIELD_FLAG(DRAW_IGNORE_COLOR_ALL);8087BIND_BITFIELD_FLAG(DRAW_CLEAR_DEPTH);8088BIND_BITFIELD_FLAG(DRAW_IGNORE_DEPTH);8089BIND_BITFIELD_FLAG(DRAW_CLEAR_STENCIL);8090BIND_BITFIELD_FLAG(DRAW_IGNORE_STENCIL);8091BIND_BITFIELD_FLAG(DRAW_CLEAR_ALL);8092BIND_BITFIELD_FLAG(DRAW_IGNORE_ALL);8093}80948095void RenderingDevice::make_current() {8096render_thread_id = Thread::get_caller_id();8097}80988099RenderingDevice::~RenderingDevice() {8100finalize();81018102if (singleton == this) {8103singleton = nullptr;8104}8105}81068107RenderingDevice::RenderingDevice() {8108if (singleton == nullptr) {8109singleton = this;8110}81118112render_thread_id = Thread::get_caller_id();8113}81148115/*****************/8116/**** BINDERS ****/8117/*****************/81188119RID RenderingDevice::_texture_create(const Ref<RDTextureFormat> &p_format, const Ref<RDTextureView> &p_view, const TypedArray<PackedByteArray> &p_data) {8120ERR_FAIL_COND_V(p_format.is_null(), RID());8121ERR_FAIL_COND_V(p_view.is_null(), RID());8122Vector<Vector<uint8_t>> data;8123for (int i = 0; i < p_data.size(); i++) {8124Vector<uint8_t> byte_slice = p_data[i];8125ERR_FAIL_COND_V(byte_slice.is_empty(), RID());8126data.push_back(byte_slice);8127}8128return texture_create(p_format->base, p_view->base, data);8129}81308131RID RenderingDevice::_texture_create_shared(const Ref<RDTextureView> &p_view, RID p_with_texture) {8132ERR_FAIL_COND_V(p_view.is_null(), RID());81338134return texture_create_shared(p_view->base, p_with_texture);8135}81368137RID RenderingDevice::_texture_create_shared_from_slice(const Ref<RDTextureView> &p_view, RID p_with_texture, uint32_t p_layer, uint32_t p_mipmap, uint32_t p_mipmaps, TextureSliceType p_slice_type) {8138ERR_FAIL_COND_V(p_view.is_null(), RID());81398140return texture_create_shared_from_slice(p_view->base, p_with_texture, p_layer, p_mipmap, p_mipmaps, p_slice_type);8141}81428143Ref<RDTextureFormat> RenderingDevice::_texture_get_format(RID p_rd_texture) {8144Ref<RDTextureFormat> rtf;8145rtf.instantiate();8146rtf->base = texture_get_format(p_rd_texture);81478148return rtf;8149}81508151RenderingDevice::FramebufferFormatID RenderingDevice::_framebuffer_format_create(const TypedArray<RDAttachmentFormat> &p_attachments, uint32_t p_view_count) {8152Vector<AttachmentFormat> attachments;8153attachments.resize(p_attachments.size());81548155for (int i = 0; i < p_attachments.size(); i++) {8156Ref<RDAttachmentFormat> af = p_attachments[i];8157ERR_FAIL_COND_V(af.is_null(), INVALID_FORMAT_ID);8158attachments.write[i] = af->base;8159}8160return framebuffer_format_create(attachments, p_view_count);8161}81628163RenderingDevice::FramebufferFormatID RenderingDevice::_framebuffer_format_create_multipass(const TypedArray<RDAttachmentFormat> &p_attachments, const TypedArray<RDFramebufferPass> &p_passes, uint32_t p_view_count) {8164Vector<AttachmentFormat> attachments;8165attachments.resize(p_attachments.size());81668167for (int i = 0; i < p_attachments.size(); i++) {8168Ref<RDAttachmentFormat> af = p_attachments[i];8169ERR_FAIL_COND_V(af.is_null(), INVALID_FORMAT_ID);8170attachments.write[i] = af->base;8171}81728173Vector<FramebufferPass> passes;8174for (int i = 0; i < p_passes.size(); i++) {8175Ref<RDFramebufferPass> pass = p_passes[i];8176ERR_CONTINUE(pass.is_null());8177passes.push_back(pass->base);8178}81798180return framebuffer_format_create_multipass(attachments, passes, p_view_count);8181}81828183RID RenderingDevice::_framebuffer_create(const TypedArray<RID> &p_textures, FramebufferFormatID p_format_check, uint32_t p_view_count) {8184Vector<RID> textures = Variant(p_textures);8185return framebuffer_create(textures, p_format_check, p_view_count);8186}81878188RID RenderingDevice::_framebuffer_create_multipass(const TypedArray<RID> &p_textures, const TypedArray<RDFramebufferPass> &p_passes, FramebufferFormatID p_format_check, uint32_t p_view_count) {8189Vector<RID> textures = Variant(p_textures);8190Vector<FramebufferPass> passes;8191for (int i = 0; i < p_passes.size(); i++) {8192Ref<RDFramebufferPass> pass = p_passes[i];8193ERR_CONTINUE(pass.is_null());8194passes.push_back(pass->base);8195}8196return framebuffer_create_multipass(textures, passes, p_format_check, p_view_count);8197}81988199RID RenderingDevice::_sampler_create(const Ref<RDSamplerState> &p_state) {8200ERR_FAIL_COND_V(p_state.is_null(), RID());82018202return sampler_create(p_state->base);8203}82048205RenderingDevice::VertexFormatID RenderingDevice::_vertex_format_create(const TypedArray<RDVertexAttribute> &p_vertex_formats) {8206Vector<VertexAttribute> descriptions;8207descriptions.resize(p_vertex_formats.size());82088209for (int i = 0; i < p_vertex_formats.size(); i++) {8210Ref<RDVertexAttribute> af = p_vertex_formats[i];8211ERR_FAIL_COND_V(af.is_null(), INVALID_FORMAT_ID);8212descriptions.write[i] = af->base;8213}8214return vertex_format_create(descriptions);8215}82168217RID RenderingDevice::_vertex_array_create(uint32_t p_vertex_count, VertexFormatID p_vertex_format, const TypedArray<RID> &p_src_buffers, const Vector<int64_t> &p_offsets) {8218Vector<RID> buffers = Variant(p_src_buffers);82198220Vector<uint64_t> offsets;8221offsets.resize(p_offsets.size());8222for (int i = 0; i < p_offsets.size(); i++) {8223offsets.write[i] = p_offsets[i];8224}82258226return vertex_array_create(p_vertex_count, p_vertex_format, buffers, offsets);8227}82288229Ref<RDShaderSPIRV> RenderingDevice::_shader_compile_spirv_from_source(const Ref<RDShaderSource> &p_source, bool p_allow_cache) {8230ERR_FAIL_COND_V(p_source.is_null(), Ref<RDShaderSPIRV>());82318232Ref<RDShaderSPIRV> bytecode;8233bytecode.instantiate();8234for (int i = 0; i < RD::SHADER_STAGE_MAX; i++) {8235String error;82368237ShaderStage stage = ShaderStage(i);8238String source = p_source->get_stage_source(stage);82398240if (!source.is_empty()) {8241Vector<uint8_t> spirv = shader_compile_spirv_from_source(stage, source, p_source->get_language(), &error, p_allow_cache);8242bytecode->set_stage_bytecode(stage, spirv);8243bytecode->set_stage_compile_error(stage, error);8244}8245}8246return bytecode;8247}82488249Vector<uint8_t> RenderingDevice::_shader_compile_binary_from_spirv(const Ref<RDShaderSPIRV> &p_spirv, const String &p_shader_name) {8250ERR_FAIL_COND_V(p_spirv.is_null(), Vector<uint8_t>());82518252Vector<ShaderStageSPIRVData> stage_data;8253for (int i = 0; i < RD::SHADER_STAGE_MAX; i++) {8254ShaderStage stage = ShaderStage(i);8255ShaderStageSPIRVData sd;8256sd.shader_stage = stage;8257String error = p_spirv->get_stage_compile_error(stage);8258ERR_FAIL_COND_V_MSG(!error.is_empty(), Vector<uint8_t>(), "Can't create a shader from an errored bytecode. Check errors in source bytecode.");8259sd.spirv = p_spirv->get_stage_bytecode(stage);8260if (sd.spirv.is_empty()) {8261continue;8262}8263stage_data.push_back(sd);8264}82658266return shader_compile_binary_from_spirv(stage_data, p_shader_name);8267}82688269RID RenderingDevice::_shader_create_from_spirv(const Ref<RDShaderSPIRV> &p_spirv, const String &p_shader_name) {8270ERR_FAIL_COND_V(p_spirv.is_null(), RID());82718272Vector<ShaderStageSPIRVData> stage_data;8273for (int i = 0; i < RD::SHADER_STAGE_MAX; i++) {8274ShaderStage stage = ShaderStage(i);8275ShaderStageSPIRVData sd;8276sd.shader_stage = stage;8277String error = p_spirv->get_stage_compile_error(stage);8278ERR_FAIL_COND_V_MSG(!error.is_empty(), RID(), "Can't create a shader from an errored bytecode. Check errors in source bytecode.");8279sd.spirv = p_spirv->get_stage_bytecode(stage);8280if (sd.spirv.is_empty()) {8281continue;8282}8283stage_data.push_back(sd);8284}8285return shader_create_from_spirv(stage_data);8286}82878288RID RenderingDevice::_uniform_set_create(const TypedArray<RDUniform> &p_uniforms, RID p_shader, uint32_t p_shader_set) {8289LocalVector<Uniform> uniforms;8290uniforms.resize(p_uniforms.size());8291for (int i = 0; i < p_uniforms.size(); i++) {8292Ref<RDUniform> uniform = p_uniforms[i];8293ERR_FAIL_COND_V(uniform.is_null(), RID());8294uniforms[i] = uniform->base;8295}8296return uniform_set_create(uniforms, p_shader, p_shader_set);8297}82988299Error RenderingDevice::_buffer_update_bind(RID p_buffer, uint32_t p_offset, uint32_t p_size, const Vector<uint8_t> &p_data) {8300return buffer_update(p_buffer, p_offset, p_size, p_data.ptr());8301}83028303static Vector<RenderingDevice::PipelineSpecializationConstant> _get_spec_constants(const TypedArray<RDPipelineSpecializationConstant> &p_constants) {8304Vector<RenderingDevice::PipelineSpecializationConstant> ret;8305ret.resize(p_constants.size());8306for (int i = 0; i < p_constants.size(); i++) {8307Ref<RDPipelineSpecializationConstant> c = p_constants[i];8308ERR_CONTINUE(c.is_null());8309RenderingDevice::PipelineSpecializationConstant &sc = ret.write[i];8310Variant value = c->get_value();8311switch (value.get_type()) {8312case Variant::BOOL: {8313sc.type = RD::PIPELINE_SPECIALIZATION_CONSTANT_TYPE_BOOL;8314sc.bool_value = value;8315} break;8316case Variant::INT: {8317sc.type = RD::PIPELINE_SPECIALIZATION_CONSTANT_TYPE_INT;8318sc.int_value = value;8319} break;8320case Variant::FLOAT: {8321sc.type = RD::PIPELINE_SPECIALIZATION_CONSTANT_TYPE_FLOAT;8322sc.float_value = value;8323} break;8324default: {8325}8326}83278328sc.constant_id = c->get_constant_id();8329}8330return ret;8331}83328333RID RenderingDevice::_render_pipeline_create(RID p_shader, FramebufferFormatID p_framebuffer_format, VertexFormatID p_vertex_format, RenderPrimitive p_render_primitive, const Ref<RDPipelineRasterizationState> &p_rasterization_state, const Ref<RDPipelineMultisampleState> &p_multisample_state, const Ref<RDPipelineDepthStencilState> &p_depth_stencil_state, const Ref<RDPipelineColorBlendState> &p_blend_state, BitField<PipelineDynamicStateFlags> p_dynamic_state_flags, uint32_t p_for_render_pass, const TypedArray<RDPipelineSpecializationConstant> &p_specialization_constants) {8334PipelineRasterizationState rasterization_state;8335if (p_rasterization_state.is_valid()) {8336rasterization_state = p_rasterization_state->base;8337}83388339PipelineMultisampleState multisample_state;8340if (p_multisample_state.is_valid()) {8341multisample_state = p_multisample_state->base;8342for (int i = 0; i < p_multisample_state->sample_masks.size(); i++) {8343int64_t mask = p_multisample_state->sample_masks[i];8344multisample_state.sample_mask.push_back(mask);8345}8346}83478348PipelineDepthStencilState depth_stencil_state;8349if (p_depth_stencil_state.is_valid()) {8350depth_stencil_state = p_depth_stencil_state->base;8351}83528353PipelineColorBlendState color_blend_state;8354if (p_blend_state.is_valid()) {8355color_blend_state = p_blend_state->base;8356for (int i = 0; i < p_blend_state->attachments.size(); i++) {8357Ref<RDPipelineColorBlendStateAttachment> attachment = p_blend_state->attachments[i];8358if (attachment.is_valid()) {8359color_blend_state.attachments.push_back(attachment->base);8360}8361}8362}83638364return render_pipeline_create(p_shader, p_framebuffer_format, p_vertex_format, p_render_primitive, rasterization_state, multisample_state, depth_stencil_state, color_blend_state, p_dynamic_state_flags, p_for_render_pass, _get_spec_constants(p_specialization_constants));8365}83668367RID RenderingDevice::_compute_pipeline_create(RID p_shader, const TypedArray<RDPipelineSpecializationConstant> &p_specialization_constants = TypedArray<RDPipelineSpecializationConstant>()) {8368return compute_pipeline_create(p_shader, _get_spec_constants(p_specialization_constants));8369}83708371#ifndef DISABLE_DEPRECATED8372Vector<int64_t> RenderingDevice::_draw_list_begin_split(RID p_framebuffer, uint32_t p_splits, 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, const TypedArray<RID> &p_storage_textures) {8373ERR_FAIL_V_MSG(Vector<int64_t>(), "Deprecated. Split draw lists are used automatically by RenderingDevice.");8374}83758376Vector<int64_t> RenderingDevice::_draw_list_switch_to_next_pass_split(uint32_t p_splits) {8377ERR_FAIL_V_MSG(Vector<int64_t>(), "Deprecated. Split draw lists are used automatically by RenderingDevice.");8378}8379#endif83808381void RenderingDevice::_draw_list_set_push_constant(DrawListID p_list, const Vector<uint8_t> &p_data, uint32_t p_data_size) {8382ERR_FAIL_COND(p_data_size > (uint32_t)p_data.size());8383draw_list_set_push_constant(p_list, p_data.ptr(), p_data_size);8384}83858386void RenderingDevice::_compute_list_set_push_constant(ComputeListID p_list, const Vector<uint8_t> &p_data, uint32_t p_data_size) {8387ERR_FAIL_COND(p_data_size > (uint32_t)p_data.size());8388compute_list_set_push_constant(p_list, p_data.ptr(), p_data_size);8389}83908391static_assert(ENUM_MEMBERS_EQUAL(RD::CALLBACK_RESOURCE_USAGE_NONE, RDG::RESOURCE_USAGE_NONE));8392static_assert(ENUM_MEMBERS_EQUAL(RD::CALLBACK_RESOURCE_USAGE_COPY_FROM, RDG::RESOURCE_USAGE_COPY_FROM));8393static_assert(ENUM_MEMBERS_EQUAL(RD::CALLBACK_RESOURCE_USAGE_COPY_TO, RDG::RESOURCE_USAGE_COPY_TO));8394static_assert(ENUM_MEMBERS_EQUAL(RD::CALLBACK_RESOURCE_USAGE_RESOLVE_FROM, RDG::RESOURCE_USAGE_RESOLVE_FROM));8395static_assert(ENUM_MEMBERS_EQUAL(RD::CALLBACK_RESOURCE_USAGE_RESOLVE_TO, RDG::RESOURCE_USAGE_RESOLVE_TO));8396static_assert(ENUM_MEMBERS_EQUAL(RD::CALLBACK_RESOURCE_USAGE_UNIFORM_BUFFER_READ, RDG::RESOURCE_USAGE_UNIFORM_BUFFER_READ));8397static_assert(ENUM_MEMBERS_EQUAL(RD::CALLBACK_RESOURCE_USAGE_INDIRECT_BUFFER_READ, RDG::RESOURCE_USAGE_INDIRECT_BUFFER_READ));8398static_assert(ENUM_MEMBERS_EQUAL(RD::CALLBACK_RESOURCE_USAGE_TEXTURE_BUFFER_READ, RDG::RESOURCE_USAGE_TEXTURE_BUFFER_READ));8399static_assert(ENUM_MEMBERS_EQUAL(RD::CALLBACK_RESOURCE_USAGE_TEXTURE_BUFFER_READ_WRITE, RDG::RESOURCE_USAGE_TEXTURE_BUFFER_READ_WRITE));8400static_assert(ENUM_MEMBERS_EQUAL(RD::CALLBACK_RESOURCE_USAGE_STORAGE_BUFFER_READ, RDG::RESOURCE_USAGE_STORAGE_BUFFER_READ));8401static_assert(ENUM_MEMBERS_EQUAL(RD::CALLBACK_RESOURCE_USAGE_STORAGE_BUFFER_READ_WRITE, RDG::RESOURCE_USAGE_STORAGE_BUFFER_READ_WRITE));8402static_assert(ENUM_MEMBERS_EQUAL(RD::CALLBACK_RESOURCE_USAGE_VERTEX_BUFFER_READ, RDG::RESOURCE_USAGE_VERTEX_BUFFER_READ));8403static_assert(ENUM_MEMBERS_EQUAL(RD::CALLBACK_RESOURCE_USAGE_INDEX_BUFFER_READ, RDG::RESOURCE_USAGE_INDEX_BUFFER_READ));8404static_assert(ENUM_MEMBERS_EQUAL(RD::CALLBACK_RESOURCE_USAGE_TEXTURE_SAMPLE, RDG::RESOURCE_USAGE_TEXTURE_SAMPLE));8405static_assert(ENUM_MEMBERS_EQUAL(RD::CALLBACK_RESOURCE_USAGE_STORAGE_IMAGE_READ, RDG::RESOURCE_USAGE_STORAGE_IMAGE_READ));8406static_assert(ENUM_MEMBERS_EQUAL(RD::CALLBACK_RESOURCE_USAGE_STORAGE_IMAGE_READ_WRITE, RDG::RESOURCE_USAGE_STORAGE_IMAGE_READ_WRITE));8407static_assert(ENUM_MEMBERS_EQUAL(RD::CALLBACK_RESOURCE_USAGE_ATTACHMENT_COLOR_READ_WRITE, RDG::RESOURCE_USAGE_ATTACHMENT_COLOR_READ_WRITE));8408static_assert(ENUM_MEMBERS_EQUAL(RD::CALLBACK_RESOURCE_USAGE_ATTACHMENT_DEPTH_STENCIL_READ_WRITE, RDG::RESOURCE_USAGE_ATTACHMENT_DEPTH_STENCIL_READ_WRITE));8409static_assert(ENUM_MEMBERS_EQUAL(RD::CALLBACK_RESOURCE_USAGE_GENERAL, RDG::RESOURCE_USAGE_GENERAL));8410static_assert(ENUM_MEMBERS_EQUAL(RD::CALLBACK_RESOURCE_USAGE_MAX, RDG::RESOURCE_USAGE_MAX));841184128413