Path: blob/master/servers/rendering/rendering_device.cpp
11351 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 "core/io/file_access.h"39#include "modules/modules_enabled.gen.h"40#include "servers/rendering/rendering_shader_container.h"4142#ifdef MODULE_GLSLANG_ENABLED43#include "modules/glslang/shader_compile.h"44#endif4546#define FORCE_SEPARATE_PRESENT_QUEUE 047#define PRINT_FRAMEBUFFER_FORMAT 04849#define ERR_RENDER_THREAD_MSG String("This function (") + String(__func__) + String(") can only be called from the render thread. ")50#define ERR_RENDER_THREAD_GUARD() ERR_FAIL_COND_MSG(render_thread_id != Thread::get_caller_id(), ERR_RENDER_THREAD_MSG);51#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);5253/**************************/54/**** HELPER FUNCTIONS ****/55/**************************/5657static String _get_device_vendor_name(const RenderingContextDriver::Device &p_device) {58switch (p_device.vendor) {59case RenderingContextDriver::Vendor::VENDOR_AMD:60return "AMD";61case RenderingContextDriver::Vendor::VENDOR_IMGTEC:62return "ImgTec";63case RenderingContextDriver::Vendor::VENDOR_APPLE:64return "Apple";65case RenderingContextDriver::Vendor::VENDOR_NVIDIA:66return "NVIDIA";67case RenderingContextDriver::Vendor::VENDOR_ARM:68return "ARM";69case RenderingContextDriver::Vendor::VENDOR_MICROSOFT:70return "Microsoft";71case RenderingContextDriver::Vendor::VENDOR_QUALCOMM:72return "Qualcomm";73case RenderingContextDriver::Vendor::VENDOR_INTEL:74return "Intel";75default:76return "Unknown";77}78}7980static String _get_device_type_name(const RenderingContextDriver::Device &p_device) {81switch (p_device.type) {82case RenderingContextDriver::DEVICE_TYPE_INTEGRATED_GPU:83return "Integrated";84case RenderingContextDriver::DEVICE_TYPE_DISCRETE_GPU:85return "Discrete";86case RenderingContextDriver::DEVICE_TYPE_VIRTUAL_GPU:87return "Virtual";88case RenderingContextDriver::DEVICE_TYPE_CPU:89return "CPU";90case RenderingContextDriver::DEVICE_TYPE_OTHER:91default:92return "Other";93}94}9596static uint32_t _get_device_type_score(const RenderingContextDriver::Device &p_device) {97static const bool prefer_integrated = OS::get_singleton()->get_user_prefers_integrated_gpu();98switch (p_device.type) {99case RenderingContextDriver::DEVICE_TYPE_INTEGRATED_GPU:100return prefer_integrated ? 5 : 4;101case RenderingContextDriver::DEVICE_TYPE_DISCRETE_GPU:102return prefer_integrated ? 4 : 5;103case RenderingContextDriver::DEVICE_TYPE_VIRTUAL_GPU:104return 3;105case RenderingContextDriver::DEVICE_TYPE_CPU:106return 2;107case RenderingContextDriver::DEVICE_TYPE_OTHER:108default:109return 1;110}111}112113/**************************/114/**** RENDERING DEVICE ****/115/**************************/116117// When true, the command graph will attempt to reorder the rendering commands submitted by the user based on the dependencies detected from118// the commands automatically. This should improve rendering performance in most scenarios at the cost of some extra CPU overhead.119//120// This behavior can be disabled if it's suspected that the graph is not detecting dependencies correctly and more control over the order of121// the commands is desired (e.g. debugging).122123#define RENDER_GRAPH_REORDER 1124125// Synchronization barriers are issued between the graph's levels only with the necessary amount of detail to achieve the correct result. If126// it's suspected that the graph is not doing this correctly, full barriers can be issued instead that will block all types of operations127// between the synchronization levels. This setting will have a very negative impact on performance when enabled, so it's only intended for128// debugging purposes.129130#define RENDER_GRAPH_FULL_BARRIERS 0131132// The command graph can automatically issue secondary command buffers and record them on background threads when they reach an arbitrary133// size threshold. This can be very beneficial towards reducing the time the main thread takes to record all the rendering commands. However,134// 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.135136#define SECONDARY_COMMAND_BUFFERS_PER_FRAME 0137138RenderingDevice *RenderingDevice::singleton = nullptr;139140RenderingDevice *RenderingDevice::get_singleton() {141return singleton;142}143144/***************************/145/**** ID INFRASTRUCTURE ****/146/***************************/147148void RenderingDevice::_add_dependency(RID p_id, RID p_depends_on) {149_THREAD_SAFE_METHOD_150151HashSet<RID> *set = dependency_map.getptr(p_depends_on);152if (set == nullptr) {153set = &dependency_map.insert(p_depends_on, HashSet<RID>())->value;154}155set->insert(p_id);156157set = reverse_dependency_map.getptr(p_id);158if (set == nullptr) {159set = &reverse_dependency_map.insert(p_id, HashSet<RID>())->value;160}161set->insert(p_depends_on);162}163164void RenderingDevice::_free_dependencies(RID p_id) {165_THREAD_SAFE_METHOD_166167// Direct dependencies must be freed.168169HashMap<RID, HashSet<RID>>::Iterator E = dependency_map.find(p_id);170if (E) {171while (E->value.size()) {172free_rid(*E->value.begin());173}174dependency_map.remove(E);175}176177// Reverse dependencies must be unreferenced.178E = reverse_dependency_map.find(p_id);179180if (E) {181for (const RID &F : E->value) {182HashMap<RID, HashSet<RID>>::Iterator G = dependency_map.find(F);183ERR_CONTINUE(!G);184ERR_CONTINUE(!G->value.has(p_id));185G->value.erase(p_id);186}187188reverse_dependency_map.remove(E);189}190}191192/*******************************/193/**** SHADER INFRASTRUCTURE ****/194/*******************************/195196Vector<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) {197switch (p_language) {198#ifdef MODULE_GLSLANG_ENABLED199case ShaderLanguage::SHADER_LANGUAGE_GLSL: {200ShaderLanguageVersion language_version = driver->get_shader_container_format().get_shader_language_version();201ShaderSpirvVersion spirv_version = driver->get_shader_container_format().get_shader_spirv_version();202return compile_glslang_shader(p_stage, ShaderIncludeDB::parse_include_files(p_source_code), language_version, spirv_version, r_error);203}204#endif205default:206ERR_FAIL_V_MSG(Vector<uint8_t>(), "Shader language is not supported.");207}208}209210RID RenderingDevice::shader_create_from_spirv(const Vector<ShaderStageSPIRVData> &p_spirv, const String &p_shader_name) {211Vector<uint8_t> bytecode = shader_compile_binary_from_spirv(p_spirv, p_shader_name);212ERR_FAIL_COND_V(bytecode.is_empty(), RID());213return shader_create_from_bytecode(bytecode);214}215216/***************************/217/**** BUFFER MANAGEMENT ****/218/***************************/219220RenderingDevice::Buffer *RenderingDevice::_get_buffer_from_owner(RID p_buffer) {221Buffer *buffer = nullptr;222if (vertex_buffer_owner.owns(p_buffer)) {223buffer = vertex_buffer_owner.get_or_null(p_buffer);224} else if (index_buffer_owner.owns(p_buffer)) {225buffer = index_buffer_owner.get_or_null(p_buffer);226} else if (uniform_buffer_owner.owns(p_buffer)) {227buffer = uniform_buffer_owner.get_or_null(p_buffer);228} else if (texture_buffer_owner.owns(p_buffer)) {229DEV_ASSERT(false && "FIXME: Broken.");230//buffer = texture_buffer_owner.get_or_null(p_buffer)->buffer;231} else if (storage_buffer_owner.owns(p_buffer)) {232buffer = storage_buffer_owner.get_or_null(p_buffer);233}234return buffer;235}236237Error RenderingDevice::_buffer_initialize(Buffer *p_buffer, Span<uint8_t> p_data, uint32_t p_required_align) {238uint32_t transfer_worker_offset;239TransferWorker *transfer_worker = _acquire_transfer_worker(p_data.size(), p_required_align, transfer_worker_offset);240p_buffer->transfer_worker_index = transfer_worker->index;241242{243MutexLock lock(transfer_worker->operations_mutex);244p_buffer->transfer_worker_operation = ++transfer_worker->operations_counter;245}246247// Copy to the worker's staging buffer.248uint8_t *data_ptr = driver->buffer_map(transfer_worker->staging_buffer);249ERR_FAIL_NULL_V(data_ptr, ERR_CANT_CREATE);250251memcpy(data_ptr + transfer_worker_offset, p_data.ptr(), p_data.size());252driver->buffer_unmap(transfer_worker->staging_buffer);253254// Copy from the staging buffer to the real buffer.255RDD::BufferCopyRegion region;256region.src_offset = transfer_worker_offset;257region.dst_offset = 0;258region.size = p_data.size();259driver->command_copy_buffer(transfer_worker->command_buffer, transfer_worker->staging_buffer, p_buffer->driver_id, region);260261_release_transfer_worker(transfer_worker);262263return OK;264}265266Error RenderingDevice::_insert_staging_block(StagingBuffers &p_staging_buffers) {267StagingBufferBlock block;268269block.driver_id = driver->buffer_create(p_staging_buffers.block_size, p_staging_buffers.usage_bits, RDD::MEMORY_ALLOCATION_TYPE_CPU);270ERR_FAIL_COND_V(!block.driver_id, ERR_CANT_CREATE);271272block.frame_used = 0;273block.fill_amount = 0;274275p_staging_buffers.blocks.insert(p_staging_buffers.current, block);276return OK;277}278279Error 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) {280// Determine a block to use.281282r_alloc_size = p_amount;283r_required_action = STAGING_REQUIRED_ACTION_NONE;284285while (true) {286r_alloc_offset = 0;287288// See if we can use current block.289if (p_staging_buffers.blocks[p_staging_buffers.current].frame_used == frames_drawn) {290// We used this block this frame, let's see if there is still room.291292uint32_t write_from = p_staging_buffers.blocks[p_staging_buffers.current].fill_amount;293294{295uint32_t align_remainder = write_from % p_required_align;296if (align_remainder != 0) {297write_from += p_required_align - align_remainder;298}299}300301int32_t available_bytes = int32_t(p_staging_buffers.block_size) - int32_t(write_from);302303if ((int32_t)p_amount < available_bytes) {304// All is good, we should be ok, all will fit.305r_alloc_offset = write_from;306} else if (p_can_segment && available_bytes >= (int32_t)p_required_align) {307// Ok all won't fit but at least we can fit a chunkie.308// All is good, update what needs to be written to.309r_alloc_offset = write_from;310r_alloc_size = available_bytes - (available_bytes % p_required_align);311312} else {313// Can't fit it into this buffer.314// Will need to try next buffer.315316p_staging_buffers.current = (p_staging_buffers.current + 1) % p_staging_buffers.blocks.size();317318// Before doing anything, though, let's check that we didn't manage to fill all blocks.319// Possible in a single frame.320if (p_staging_buffers.blocks[p_staging_buffers.current].frame_used == frames_drawn) {321// Guess we did.. ok, let's see if we can insert a new block.322if ((uint64_t)p_staging_buffers.blocks.size() * p_staging_buffers.block_size < p_staging_buffers.max_size) {323// We can, so we are safe.324Error err = _insert_staging_block(p_staging_buffers);325if (err) {326return err;327}328// Claim for this frame.329p_staging_buffers.blocks.write[p_staging_buffers.current].frame_used = frames_drawn;330} else {331// Ok, worst case scenario, all the staging buffers belong to this frame332// and this frame is not even done.333// If this is the main thread, it means the user is likely loading a lot of resources at once,.334// Otherwise, the thread should just be blocked until the next frame (currently unimplemented).335r_required_action = STAGING_REQUIRED_ACTION_FLUSH_AND_STALL_ALL;336}337338} else {339// Not from current frame, so continue and try again.340continue;341}342}343344} else if (p_staging_buffers.blocks[p_staging_buffers.current].frame_used <= frames_drawn - frames.size()) {345// This is an old block, which was already processed, let's reuse.346p_staging_buffers.blocks.write[p_staging_buffers.current].frame_used = frames_drawn;347p_staging_buffers.blocks.write[p_staging_buffers.current].fill_amount = 0;348} else {349// This block may still be in use, let's not touch it unless we have to, so.. can we create a new one?350if ((uint64_t)p_staging_buffers.blocks.size() * p_staging_buffers.block_size < p_staging_buffers.max_size) {351// We are still allowed to create a new block, so let's do that and insert it for current pos.352Error err = _insert_staging_block(p_staging_buffers);353if (err) {354return err;355}356// Claim for this frame.357p_staging_buffers.blocks.write[p_staging_buffers.current].frame_used = frames_drawn;358} else {359// Oops, we are out of room and we can't create more.360// Let's flush older frames.361// 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.362// If loading from a separate thread, we can block that thread until next frame when more room is made (not currently implemented, though).363r_required_action = STAGING_REQUIRED_ACTION_STALL_PREVIOUS;364}365}366367// All was good, break.368break;369}370371p_staging_buffers.used = true;372373return OK;374}375376void RenderingDevice::_staging_buffer_execute_required_action(StagingBuffers &p_staging_buffers, StagingRequiredAction p_required_action) {377switch (p_required_action) {378case STAGING_REQUIRED_ACTION_NONE: {379// Do nothing.380} break;381case STAGING_REQUIRED_ACTION_FLUSH_AND_STALL_ALL: {382_flush_and_stall_for_all_frames();383384// Clear the whole staging buffer.385for (int i = 0; i < p_staging_buffers.blocks.size(); i++) {386p_staging_buffers.blocks.write[i].frame_used = 0;387p_staging_buffers.blocks.write[i].fill_amount = 0;388}389390// Claim for current frame.391p_staging_buffers.blocks.write[p_staging_buffers.current].frame_used = frames_drawn;392} break;393case STAGING_REQUIRED_ACTION_STALL_PREVIOUS: {394_stall_for_previous_frames();395396for (int i = 0; i < p_staging_buffers.blocks.size(); i++) {397// Clear all blocks but the ones from this frame.398int block_idx = (i + p_staging_buffers.current) % p_staging_buffers.blocks.size();399if (p_staging_buffers.blocks[block_idx].frame_used == frames_drawn) {400break; // Ok, we reached something from this frame, abort.401}402403p_staging_buffers.blocks.write[block_idx].frame_used = 0;404p_staging_buffers.blocks.write[block_idx].fill_amount = 0;405}406407// Claim for current frame.408p_staging_buffers.blocks.write[p_staging_buffers.current].frame_used = frames_drawn;409} break;410default: {411DEV_ASSERT(false && "Unknown required action.");412} break;413}414}415416Error 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) {417ERR_RENDER_THREAD_GUARD_V(ERR_UNAVAILABLE);418419ERR_FAIL_COND_V_MSG(draw_list.active, ERR_INVALID_PARAMETER,420"Copying buffers is forbidden during creation of a draw list");421ERR_FAIL_COND_V_MSG(compute_list.active, ERR_INVALID_PARAMETER,422"Copying buffers is forbidden during creation of a compute list");423424Buffer *src_buffer = _get_buffer_from_owner(p_src_buffer);425if (!src_buffer) {426ERR_FAIL_V_MSG(ERR_INVALID_PARAMETER, "Source buffer argument is not a valid buffer of any type.");427}428429Buffer *dst_buffer = _get_buffer_from_owner(p_dst_buffer);430if (!dst_buffer) {431ERR_FAIL_V_MSG(ERR_INVALID_PARAMETER, "Destination buffer argument is not a valid buffer of any type.");432}433434// Validate the copy's dimensions for both buffers.435ERR_FAIL_COND_V_MSG((p_size + p_src_offset) > src_buffer->size, ERR_INVALID_PARAMETER, "Size is larger than the source buffer.");436ERR_FAIL_COND_V_MSG((p_size + p_dst_offset) > dst_buffer->size, ERR_INVALID_PARAMETER, "Size is larger than the destination buffer.");437438_check_transfer_worker_buffer(src_buffer);439_check_transfer_worker_buffer(dst_buffer);440441// Perform the copy.442RDD::BufferCopyRegion region;443region.src_offset = p_src_offset;444region.dst_offset = p_dst_offset;445region.size = p_size;446447if (_buffer_make_mutable(dst_buffer, p_dst_buffer)) {448// The destination buffer must be mutable to be used as a copy destination.449draw_graph.add_synchronization();450}451452draw_graph.add_buffer_copy(src_buffer->driver_id, src_buffer->draw_tracker, dst_buffer->driver_id, dst_buffer->draw_tracker, region);453454return OK;455}456457Error RenderingDevice::buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p_size, const void *p_data) {458ERR_RENDER_THREAD_GUARD_V(ERR_UNAVAILABLE);459460copy_bytes_count += p_size;461ERR_FAIL_COND_V_MSG(draw_list.active, ERR_INVALID_PARAMETER,462"Updating buffers is forbidden during creation of a draw list");463ERR_FAIL_COND_V_MSG(compute_list.active, ERR_INVALID_PARAMETER,464"Updating buffers is forbidden during creation of a compute list");465466Buffer *buffer = _get_buffer_from_owner(p_buffer);467ERR_FAIL_NULL_V_MSG(buffer, ERR_INVALID_PARAMETER, "Buffer argument is not a valid buffer of any type.");468ERR_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.");469470_check_transfer_worker_buffer(buffer);471472// Submitting may get chunked for various reasons, so convert this to a task.473size_t to_submit = p_size;474size_t submit_from = 0;475476thread_local LocalVector<RDG::RecordedBufferCopy> command_buffer_copies_vector;477command_buffer_copies_vector.clear();478479const uint8_t *src_data = reinterpret_cast<const uint8_t *>(p_data);480const uint32_t required_align = 32;481while (to_submit > 0) {482uint32_t block_write_offset;483uint32_t block_write_amount;484StagingRequiredAction required_action;485486Error 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);487if (err) {488return err;489}490491if (!command_buffer_copies_vector.is_empty() && required_action == STAGING_REQUIRED_ACTION_FLUSH_AND_STALL_ALL) {492if (_buffer_make_mutable(buffer, p_buffer)) {493// The buffer must be mutable to be used as a copy destination.494draw_graph.add_synchronization();495}496497draw_graph.add_buffer_update(buffer->driver_id, buffer->draw_tracker, command_buffer_copies_vector);498command_buffer_copies_vector.clear();499}500501_staging_buffer_execute_required_action(upload_staging_buffers, required_action);502503// Map staging buffer (It's CPU and coherent).504uint8_t *data_ptr = driver->buffer_map(upload_staging_buffers.blocks[upload_staging_buffers.current].driver_id);505ERR_FAIL_NULL_V(data_ptr, ERR_CANT_CREATE);506507// Copy to staging buffer.508memcpy(data_ptr + block_write_offset, src_data + submit_from, block_write_amount);509510// Unmap.511driver->buffer_unmap(upload_staging_buffers.blocks[upload_staging_buffers.current].driver_id);512513// Insert a command to copy this.514RDD::BufferCopyRegion region;515region.src_offset = block_write_offset;516region.dst_offset = submit_from + p_offset;517region.size = block_write_amount;518519RDG::RecordedBufferCopy buffer_copy;520buffer_copy.source = upload_staging_buffers.blocks[upload_staging_buffers.current].driver_id;521buffer_copy.region = region;522command_buffer_copies_vector.push_back(buffer_copy);523524upload_staging_buffers.blocks.write[upload_staging_buffers.current].fill_amount = block_write_offset + block_write_amount;525526to_submit -= block_write_amount;527submit_from += block_write_amount;528}529530if (!command_buffer_copies_vector.is_empty()) {531if (_buffer_make_mutable(buffer, p_buffer)) {532// The buffer must be mutable to be used as a copy destination.533draw_graph.add_synchronization();534}535536draw_graph.add_buffer_update(buffer->driver_id, buffer->draw_tracker, command_buffer_copies_vector);537}538539gpu_copy_count++;540541return OK;542}543544Error RenderingDevice::driver_callback_add(RDD::DriverCallback p_callback, void *p_userdata, VectorView<CallbackResource> p_resources) {545ERR_RENDER_THREAD_GUARD_V(ERR_UNAVAILABLE);546547ERR_FAIL_COND_V_MSG(draw_list.active, ERR_INVALID_PARAMETER,548"Driver callback is forbidden during creation of a draw list");549ERR_FAIL_COND_V_MSG(compute_list.active, ERR_INVALID_PARAMETER,550"Driver callback is forbidden during creation of a compute list");551552thread_local LocalVector<RDG::ResourceTracker *> trackers;553thread_local LocalVector<RDG::ResourceUsage> usages;554555uint32_t resource_count = p_resources.size();556trackers.resize(resource_count);557usages.resize(resource_count);558559if (resource_count > 0) {560for (uint32_t i = 0; i < p_resources.size(); i++) {561const CallbackResource &cr = p_resources[i];562switch (cr.type) {563case CALLBACK_RESOURCE_TYPE_BUFFER: {564Buffer *buffer = _get_buffer_from_owner(cr.rid);565if (!buffer) {566ERR_FAIL_V_MSG(ERR_INVALID_PARAMETER, vformat("Argument %d is not a valid buffer of any type.", i));567}568if (_buffer_make_mutable(buffer, cr.rid)) {569draw_graph.add_synchronization();570}571trackers[i] = buffer->draw_tracker;572usages[i] = (RDG::ResourceUsage)cr.usage;573} break;574case CALLBACK_RESOURCE_TYPE_TEXTURE: {575Texture *texture = texture_owner.get_or_null(cr.rid);576if (!texture) {577ERR_FAIL_V_MSG(ERR_INVALID_PARAMETER, vformat("Argument %d is not a valid texture.", i));578}579if (_texture_make_mutable(texture, cr.rid)) {580draw_graph.add_synchronization();581}582trackers[i] = texture->draw_tracker;583usages[i] = (RDG::ResourceUsage)cr.usage;584} break;585default: {586CRASH_NOW_MSG("Invalid callback resource type.");587} break;588}589}590}591592draw_graph.add_driver_callback(p_callback, p_userdata, trackers, usages);593594return OK;595}596597String RenderingDevice::get_perf_report() const {598String perf_report_text;599perf_report_text += " gpu:" + String::num_int64(prev_gpu_copy_count);600perf_report_text += " bytes:" + String::num_int64(prev_copy_bytes_count);601602perf_report_text += " lazily alloc:" + String::num_int64(driver->get_lazily_memory_used());603return perf_report_text;604}605606void RenderingDevice::update_perf_report() {607prev_gpu_copy_count = gpu_copy_count;608prev_copy_bytes_count = copy_bytes_count;609gpu_copy_count = 0;610copy_bytes_count = 0;611}612613Error RenderingDevice::buffer_clear(RID p_buffer, uint32_t p_offset, uint32_t p_size) {614ERR_RENDER_THREAD_GUARD_V(ERR_UNAVAILABLE);615616ERR_FAIL_COND_V_MSG((p_size % 4) != 0, ERR_INVALID_PARAMETER,617"Size must be a multiple of four");618ERR_FAIL_COND_V_MSG(draw_list.active, ERR_INVALID_PARAMETER,619"Updating buffers in is forbidden during creation of a draw list");620ERR_FAIL_COND_V_MSG(compute_list.active, ERR_INVALID_PARAMETER,621"Updating buffers is forbidden during creation of a compute list");622623Buffer *buffer = _get_buffer_from_owner(p_buffer);624if (!buffer) {625ERR_FAIL_V_MSG(ERR_INVALID_PARAMETER, "Buffer argument is not a valid buffer of any type.");626}627628ERR_FAIL_COND_V_MSG(p_offset + p_size > buffer->size, ERR_INVALID_PARAMETER,629"Attempted to write buffer (" + itos((p_offset + p_size) - buffer->size) + " bytes) past the end.");630631_check_transfer_worker_buffer(buffer);632633if (_buffer_make_mutable(buffer, p_buffer)) {634// The destination buffer must be mutable to be used as a clear destination.635draw_graph.add_synchronization();636}637638draw_graph.add_buffer_clear(buffer->driver_id, buffer->draw_tracker, p_offset, p_size);639640return OK;641}642643Vector<uint8_t> RenderingDevice::buffer_get_data(RID p_buffer, uint32_t p_offset, uint32_t p_size) {644ERR_RENDER_THREAD_GUARD_V(Vector<uint8_t>());645646Buffer *buffer = _get_buffer_from_owner(p_buffer);647if (!buffer) {648ERR_FAIL_V_MSG(Vector<uint8_t>(), "Buffer is either invalid or this type of buffer can't be retrieved.");649}650651// Size of buffer to retrieve.652if (!p_size) {653p_size = buffer->size;654} else {655ERR_FAIL_COND_V_MSG(p_size + p_offset > buffer->size, Vector<uint8_t>(),656"Size is larger than the buffer.");657}658659_check_transfer_worker_buffer(buffer);660661RDD::BufferID tmp_buffer = driver->buffer_create(buffer->size, RDD::BUFFER_USAGE_TRANSFER_TO_BIT, RDD::MEMORY_ALLOCATION_TYPE_CPU);662ERR_FAIL_COND_V(!tmp_buffer, Vector<uint8_t>());663664RDD::BufferCopyRegion region;665region.src_offset = p_offset;666region.size = p_size;667668draw_graph.add_buffer_get_data(buffer->driver_id, buffer->draw_tracker, tmp_buffer, region);669670// Flush everything so memory can be safely mapped.671_flush_and_stall_for_all_frames();672673uint8_t *buffer_mem = driver->buffer_map(tmp_buffer);674ERR_FAIL_NULL_V(buffer_mem, Vector<uint8_t>());675676Vector<uint8_t> buffer_data;677{678buffer_data.resize(p_size);679uint8_t *w = buffer_data.ptrw();680memcpy(w, buffer_mem, p_size);681}682683driver->buffer_unmap(tmp_buffer);684685driver->buffer_free(tmp_buffer);686687return buffer_data;688}689690Error RenderingDevice::buffer_get_data_async(RID p_buffer, const Callable &p_callback, uint32_t p_offset, uint32_t p_size) {691ERR_RENDER_THREAD_GUARD_V(ERR_UNAVAILABLE);692693Buffer *buffer = _get_buffer_from_owner(p_buffer);694if (buffer == nullptr) {695ERR_FAIL_V_MSG(ERR_INVALID_PARAMETER, "Buffer is either invalid or this type of buffer can't be retrieved.");696}697698if (p_size == 0) {699p_size = buffer->size;700}701702ERR_FAIL_COND_V_MSG(p_size + p_offset > buffer->size, ERR_INVALID_PARAMETER, "Size is larger than the buffer.");703ERR_FAIL_COND_V_MSG(!p_callback.is_valid(), ERR_INVALID_PARAMETER, "Callback must be valid.");704705_check_transfer_worker_buffer(buffer);706707BufferGetDataRequest get_data_request;708get_data_request.callback = p_callback;709get_data_request.frame_local_index = frames[frame].download_buffer_copy_regions.size();710get_data_request.size = p_size;711712const uint32_t required_align = 32;713uint32_t block_write_offset;714uint32_t block_write_amount;715StagingRequiredAction required_action;716uint32_t to_submit = p_size;717uint32_t submit_from = 0;718while (to_submit > 0) {719Error 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);720if (err) {721return err;722}723724const bool flush_frames = (get_data_request.frame_local_count > 0) && required_action == STAGING_REQUIRED_ACTION_FLUSH_AND_STALL_ALL;725if (flush_frames) {726if (_buffer_make_mutable(buffer, p_buffer)) {727// The buffer must be mutable to be used as a copy source.728draw_graph.add_synchronization();729}730731for (uint32_t i = 0; i < get_data_request.frame_local_count; i++) {732uint32_t local_index = get_data_request.frame_local_index + i;733draw_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]);734}735}736737_staging_buffer_execute_required_action(download_staging_buffers, required_action);738739if (flush_frames) {740get_data_request.frame_local_count = 0;741get_data_request.frame_local_index = frames[frame].download_buffer_copy_regions.size();742}743744RDD::BufferCopyRegion region;745region.src_offset = submit_from + p_offset;746region.dst_offset = block_write_offset;747region.size = block_write_amount;748749frames[frame].download_buffer_staging_buffers.push_back(download_staging_buffers.blocks[download_staging_buffers.current].driver_id);750frames[frame].download_buffer_copy_regions.push_back(region);751get_data_request.frame_local_count++;752753download_staging_buffers.blocks.write[download_staging_buffers.current].fill_amount = block_write_offset + block_write_amount;754755to_submit -= block_write_amount;756submit_from += block_write_amount;757}758759if (get_data_request.frame_local_count > 0) {760if (_buffer_make_mutable(buffer, p_buffer)) {761// The buffer must be mutable to be used as a copy source.762draw_graph.add_synchronization();763}764765for (uint32_t i = 0; i < get_data_request.frame_local_count; i++) {766uint32_t local_index = get_data_request.frame_local_index + i;767draw_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]);768}769770frames[frame].download_buffer_get_data_requests.push_back(get_data_request);771}772773return OK;774}775776uint64_t RenderingDevice::buffer_get_device_address(RID p_buffer) {777ERR_RENDER_THREAD_GUARD_V(0);778779Buffer *buffer = _get_buffer_from_owner(p_buffer);780ERR_FAIL_NULL_V_MSG(buffer, 0, "Buffer argument is not a valid buffer of any type.");781ERR_FAIL_COND_V_MSG(!buffer->usage.has_flag(RDD::BUFFER_USAGE_DEVICE_ADDRESS_BIT), 0, "Buffer was not created with device address flag.");782783return driver->buffer_get_device_address(buffer->driver_id);784}785786RID RenderingDevice::storage_buffer_create(uint32_t p_size_bytes, Span<uint8_t> p_data, BitField<StorageBufferUsage> p_usage, BitField<BufferCreationBits> p_creation_bits) {787ERR_FAIL_COND_V(p_data.size() && (uint32_t)p_data.size() != p_size_bytes, RID());788789Buffer buffer;790buffer.size = p_size_bytes;791buffer.usage = (RDD::BUFFER_USAGE_TRANSFER_FROM_BIT | RDD::BUFFER_USAGE_TRANSFER_TO_BIT | RDD::BUFFER_USAGE_STORAGE_BIT);792if (p_usage.has_flag(STORAGE_BUFFER_USAGE_DISPATCH_INDIRECT)) {793buffer.usage.set_flag(RDD::BUFFER_USAGE_INDIRECT_BIT);794}795if (p_creation_bits.has_flag(BUFFER_CREATION_DEVICE_ADDRESS_BIT)) {796#ifdef DEBUG_ENABLED797ERR_FAIL_COND_V_MSG(!has_feature(SUPPORTS_BUFFER_DEVICE_ADDRESS), RID(),798"The GPU doesn't support buffer address flag.");799#endif800801buffer.usage.set_flag(RDD::BUFFER_USAGE_DEVICE_ADDRESS_BIT);802}803buffer.driver_id = driver->buffer_create(buffer.size, buffer.usage, RDD::MEMORY_ALLOCATION_TYPE_GPU);804ERR_FAIL_COND_V(!buffer.driver_id, RID());805806// Storage buffers are assumed to be mutable.807buffer.draw_tracker = RDG::resource_tracker_create();808buffer.draw_tracker->buffer_driver_id = buffer.driver_id;809810if (p_data.size()) {811_buffer_initialize(&buffer, p_data);812}813814_THREAD_SAFE_LOCK_815buffer_memory += buffer.size;816_THREAD_SAFE_UNLOCK_817818RID id = storage_buffer_owner.make_rid(buffer);819#ifdef DEV_ENABLED820set_resource_name(id, "RID:" + itos(id.get_id()));821#endif822return id;823}824825RID RenderingDevice::texture_buffer_create(uint32_t p_size_elements, DataFormat p_format, Span<uint8_t> p_data) {826uint32_t element_size = get_format_vertex_size(p_format);827ERR_FAIL_COND_V_MSG(element_size == 0, RID(), "Format requested is not supported for texture buffers");828uint64_t size_bytes = uint64_t(element_size) * p_size_elements;829830ERR_FAIL_COND_V(p_data.size() && (uint32_t)p_data.size() != size_bytes, RID());831832Buffer texture_buffer;833texture_buffer.size = size_bytes;834BitField<RDD::BufferUsageBits> usage = (RDD::BUFFER_USAGE_TRANSFER_FROM_BIT | RDD::BUFFER_USAGE_TRANSFER_TO_BIT | RDD::BUFFER_USAGE_TEXEL_BIT);835texture_buffer.driver_id = driver->buffer_create(size_bytes, usage, RDD::MEMORY_ALLOCATION_TYPE_GPU);836ERR_FAIL_COND_V(!texture_buffer.driver_id, RID());837838// Texture buffers are assumed to be immutable unless they don't have initial data.839if (p_data.is_empty()) {840texture_buffer.draw_tracker = RDG::resource_tracker_create();841texture_buffer.draw_tracker->buffer_driver_id = texture_buffer.driver_id;842}843844bool ok = driver->buffer_set_texel_format(texture_buffer.driver_id, p_format);845if (!ok) {846driver->buffer_free(texture_buffer.driver_id);847ERR_FAIL_V(RID());848}849850if (p_data.size()) {851_buffer_initialize(&texture_buffer, p_data);852}853854_THREAD_SAFE_LOCK_855buffer_memory += size_bytes;856_THREAD_SAFE_UNLOCK_857858RID id = texture_buffer_owner.make_rid(texture_buffer);859#ifdef DEV_ENABLED860set_resource_name(id, "RID:" + itos(id.get_id()));861#endif862return id;863}864865/*****************/866/**** TEXTURE ****/867/*****************/868869RID RenderingDevice::texture_create(const TextureFormat &p_format, const TextureView &p_view, const Vector<Vector<uint8_t>> &p_data) {870// Some adjustments will happen.871TextureFormat format = p_format;872873if (format.shareable_formats.size()) {874ERR_FAIL_COND_V_MSG(!format.shareable_formats.has(format.format), RID(),875"If supplied a list of shareable formats, the current format must be present in the list");876ERR_FAIL_COND_V_MSG(p_view.format_override != DATA_FORMAT_MAX && !format.shareable_formats.has(p_view.format_override), RID(),877"If supplied a list of shareable formats, the current view format override must be present in the list");878}879880ERR_FAIL_INDEX_V(format.texture_type, RDD::TEXTURE_TYPE_MAX, RID());881882ERR_FAIL_COND_V_MSG(format.width < 1, RID(), "Width must be equal or greater than 1 for all textures");883884if (format.texture_type != TEXTURE_TYPE_1D && format.texture_type != TEXTURE_TYPE_1D_ARRAY) {885ERR_FAIL_COND_V_MSG(format.height < 1, RID(), "Height must be equal or greater than 1 for 2D and 3D textures");886}887888if (format.texture_type == TEXTURE_TYPE_3D) {889ERR_FAIL_COND_V_MSG(format.depth < 1, RID(), "Depth must be equal or greater than 1 for 3D textures");890}891892ERR_FAIL_COND_V(format.mipmaps < 1, RID());893894if (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) {895ERR_FAIL_COND_V_MSG(format.array_layers < 1, RID(),896"Number of layers must be equal or greater than 1 for arrays and cubemaps.");897ERR_FAIL_COND_V_MSG((format.texture_type == TEXTURE_TYPE_CUBE_ARRAY || format.texture_type == TEXTURE_TYPE_CUBE) && (format.array_layers % 6) != 0, RID(),898"Cubemap and cubemap array textures must provide a layer number that is multiple of 6");899ERR_FAIL_COND_V_MSG(((format.texture_type == TEXTURE_TYPE_CUBE_ARRAY || format.texture_type == TEXTURE_TYPE_CUBE)) && (format.width != format.height), RID(),900"Cubemap and cubemap array textures must have equal width and height.");901ERR_FAIL_COND_V_MSG(format.array_layers > driver->limit_get(LIMIT_MAX_TEXTURE_ARRAY_LAYERS), RID(), "Number of layers exceeds device maximum.");902} else {903format.array_layers = 1;904}905906ERR_FAIL_INDEX_V(format.samples, TEXTURE_SAMPLES_MAX, RID());907908ERR_FAIL_COND_V_MSG(format.usage_bits == 0, RID(), "No usage bits specified (at least one is needed)");909910format.height = format.texture_type != TEXTURE_TYPE_1D && format.texture_type != TEXTURE_TYPE_1D_ARRAY ? format.height : 1;911format.depth = format.texture_type == TEXTURE_TYPE_3D ? format.depth : 1;912913uint64_t size_max = 0;914switch (format.texture_type) {915case TEXTURE_TYPE_1D:916case TEXTURE_TYPE_1D_ARRAY:917size_max = driver->limit_get(LIMIT_MAX_TEXTURE_SIZE_1D);918break;919case TEXTURE_TYPE_2D:920case TEXTURE_TYPE_2D_ARRAY:921size_max = driver->limit_get(LIMIT_MAX_TEXTURE_SIZE_2D);922break;923case TEXTURE_TYPE_CUBE:924case TEXTURE_TYPE_CUBE_ARRAY:925size_max = driver->limit_get(LIMIT_MAX_TEXTURE_SIZE_CUBE);926break;927case TEXTURE_TYPE_3D:928size_max = driver->limit_get(LIMIT_MAX_TEXTURE_SIZE_3D);929break;930case TEXTURE_TYPE_MAX:931break;932}933ERR_FAIL_COND_V_MSG(format.width > size_max || format.height > size_max || format.depth > size_max, RID(), "Texture dimensions exceed device maximum.");934935uint32_t required_mipmaps = get_image_required_mipmaps(format.width, format.height, format.depth);936937ERR_FAIL_COND_V_MSG(required_mipmaps < format.mipmaps, RID(),938"Too many mipmaps requested for texture format and dimensions (" + itos(format.mipmaps) + "), maximum allowed: (" + itos(required_mipmaps) + ").");939940Vector<Vector<uint8_t>> data = p_data;941bool immediate_flush = false;942943// 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 1944// (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.945if (data.is_empty() && (p_format.usage_bits & TEXTURE_USAGE_VRS_ATTACHMENT_BIT)) {946immediate_flush = true;947for (uint32_t i = 0; i < format.array_layers; i++) {948uint32_t required_size = get_image_format_required_size(format.format, format.width, format.height, format.depth, format.mipmaps);949Vector<uint8_t> layer;950layer.resize(required_size);951layer.fill(255);952data.push_back(layer);953}954}955956uint32_t forced_usage_bits = _texture_vrs_method_to_usage_bits();957if (data.size()) {958ERR_FAIL_COND_V_MSG(data.size() != (int)format.array_layers, RID(),959"Default supplied data for image format is of invalid length (" + itos(data.size()) + "), should be (" + itos(format.array_layers) + ").");960961for (uint32_t i = 0; i < format.array_layers; i++) {962uint32_t required_size = get_image_format_required_size(format.format, format.width, format.height, format.depth, format.mipmaps);963ERR_FAIL_COND_V_MSG((uint32_t)data[i].size() != required_size, RID(),964"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) + ").");965}966967ERR_FAIL_COND_V_MSG(format.usage_bits & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, RID(),968"Textures created as depth attachments can't be initialized with data directly. Use RenderingDevice::texture_update() instead.");969970if (!(format.usage_bits & TEXTURE_USAGE_CAN_UPDATE_BIT)) {971forced_usage_bits |= TEXTURE_USAGE_CAN_UPDATE_BIT;972}973}974975{976// Validate that this image is supported for the intended use.977bool cpu_readable = (format.usage_bits & RDD::TEXTURE_USAGE_CPU_READ_BIT);978BitField<RDD::TextureUsageBits> supported_usage = driver->texture_get_usages_supported_by_format(format.format, cpu_readable);979980String format_text = "'" + String(FORMAT_NAMES[format.format]) + "'";981982if ((format.usage_bits & TEXTURE_USAGE_SAMPLING_BIT) && !supported_usage.has_flag(TEXTURE_USAGE_SAMPLING_BIT)) {983ERR_FAIL_V_MSG(RID(), "Format " + format_text + " does not support usage as sampling texture.");984}985if ((format.usage_bits & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) && !supported_usage.has_flag(TEXTURE_USAGE_COLOR_ATTACHMENT_BIT)) {986ERR_FAIL_V_MSG(RID(), "Format " + format_text + " does not support usage as color attachment.");987}988if ((format.usage_bits & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) && !supported_usage.has_flag(TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) {989ERR_FAIL_V_MSG(RID(), "Format " + format_text + " does not support usage as depth-stencil attachment.");990}991if ((format.usage_bits & TEXTURE_USAGE_STORAGE_BIT) && !supported_usage.has_flag(TEXTURE_USAGE_STORAGE_BIT)) {992ERR_FAIL_V_MSG(RID(), "Format " + format_text + " does not support usage as storage image.");993}994if ((format.usage_bits & TEXTURE_USAGE_STORAGE_ATOMIC_BIT) && !supported_usage.has_flag(TEXTURE_USAGE_STORAGE_ATOMIC_BIT)) {995ERR_FAIL_V_MSG(RID(), "Format " + format_text + " does not support usage as atomic storage image.");996}997if ((format.usage_bits & TEXTURE_USAGE_VRS_ATTACHMENT_BIT) && !supported_usage.has_flag(TEXTURE_USAGE_VRS_ATTACHMENT_BIT)) {998ERR_FAIL_V_MSG(RID(), "Format " + format_text + " does not support usage as variable shading rate attachment.");999}1000}10011002// Transfer and validate view info.10031004RDD::TextureView tv;1005if (p_view.format_override == DATA_FORMAT_MAX) {1006tv.format = format.format;1007} else {1008ERR_FAIL_INDEX_V(p_view.format_override, DATA_FORMAT_MAX, RID());1009tv.format = p_view.format_override;1010}1011ERR_FAIL_INDEX_V(p_view.swizzle_r, TEXTURE_SWIZZLE_MAX, RID());1012ERR_FAIL_INDEX_V(p_view.swizzle_g, TEXTURE_SWIZZLE_MAX, RID());1013ERR_FAIL_INDEX_V(p_view.swizzle_b, TEXTURE_SWIZZLE_MAX, RID());1014ERR_FAIL_INDEX_V(p_view.swizzle_a, TEXTURE_SWIZZLE_MAX, RID());1015tv.swizzle_r = p_view.swizzle_r;1016tv.swizzle_g = p_view.swizzle_g;1017tv.swizzle_b = p_view.swizzle_b;1018tv.swizzle_a = p_view.swizzle_a;10191020// Create.10211022Texture texture;1023format.usage_bits |= forced_usage_bits;1024texture.driver_id = driver->texture_create(format, tv);1025ERR_FAIL_COND_V(!texture.driver_id, RID());1026texture.type = format.texture_type;1027texture.format = format.format;1028texture.width = format.width;1029texture.height = format.height;1030texture.depth = format.depth;1031texture.layers = format.array_layers;1032texture.mipmaps = format.mipmaps;1033texture.base_mipmap = 0;1034texture.base_layer = 0;1035texture.is_resolve_buffer = format.is_resolve_buffer;1036texture.is_discardable = format.is_discardable;1037texture.usage_flags = format.usage_bits & ~forced_usage_bits;1038texture.samples = format.samples;1039texture.allowed_shared_formats = format.shareable_formats;1040texture.has_initial_data = !data.is_empty();10411042if ((format.usage_bits & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) {1043texture.read_aspect_flags.set_flag(RDD::TEXTURE_ASPECT_DEPTH_BIT);1044texture.barrier_aspect_flags.set_flag(RDD::TEXTURE_ASPECT_DEPTH_BIT);1045if (format_has_stencil(format.format)) {1046texture.barrier_aspect_flags.set_flag(RDD::TEXTURE_ASPECT_STENCIL_BIT);1047}1048} else {1049texture.read_aspect_flags.set_flag(RDD::TEXTURE_ASPECT_COLOR_BIT);1050texture.barrier_aspect_flags.set_flag(RDD::TEXTURE_ASPECT_COLOR_BIT);1051}10521053texture.bound = false;10541055// Textures are only assumed to be immutable if they have initial data and none of the other bits that indicate write usage are enabled.1056bool 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);1057if (data.is_empty() || texture_mutable_by_default) {1058_texture_make_mutable(&texture, RID());1059}10601061texture_memory += driver->texture_get_allocation_size(texture.driver_id);10621063RID id = texture_owner.make_rid(texture);1064#ifdef DEV_ENABLED1065set_resource_name(id, "RID:" + itos(id.get_id()));1066#endif10671068if (data.size()) {1069const bool use_general_in_copy_queues = driver->api_trait_get(RDD::API_TRAIT_USE_GENERAL_IN_COPY_QUEUES);1070const RDD::TextureLayout dst_layout = use_general_in_copy_queues ? RDD::TEXTURE_LAYOUT_GENERAL : RDD::TEXTURE_LAYOUT_COPY_DST_OPTIMAL;1071for (uint32_t i = 0; i < format.array_layers; i++) {1072_texture_initialize(id, i, data[i], dst_layout, immediate_flush);1073}10741075if (texture.draw_tracker != nullptr) {1076texture.draw_tracker->usage = use_general_in_copy_queues ? RDG::RESOURCE_USAGE_GENERAL : RDG::RESOURCE_USAGE_COPY_TO;1077}1078}10791080return id;1081}10821083RID RenderingDevice::texture_create_shared(const TextureView &p_view, RID p_with_texture) {1084Texture *src_texture = texture_owner.get_or_null(p_with_texture);1085ERR_FAIL_NULL_V(src_texture, RID());10861087if (src_texture->owner.is_valid()) { // Ahh this is a share. The RenderingDeviceDriver needs the actual owner.1088p_with_texture = src_texture->owner;1089src_texture = texture_owner.get_or_null(src_texture->owner);1090ERR_FAIL_NULL_V(src_texture, RID()); // This is a bug.1091}10921093// Create view.10941095Texture texture = *src_texture;1096texture.slice_trackers = nullptr;1097texture.shared_fallback = nullptr;10981099RDD::TextureView tv;1100bool create_shared = true;1101bool raw_reintepretation = false;1102if (p_view.format_override == DATA_FORMAT_MAX || p_view.format_override == texture.format) {1103tv.format = texture.format;1104} else {1105ERR_FAIL_INDEX_V(p_view.format_override, DATA_FORMAT_MAX, RID());11061107ERR_FAIL_COND_V_MSG(!texture.allowed_shared_formats.has(p_view.format_override), RID(),1108"Format override is not in the list of allowed shareable formats for original texture.");1109tv.format = p_view.format_override;1110create_shared = driver->texture_can_make_shared_with_format(texture.driver_id, p_view.format_override, raw_reintepretation);1111}1112tv.swizzle_r = p_view.swizzle_r;1113tv.swizzle_g = p_view.swizzle_g;1114tv.swizzle_b = p_view.swizzle_b;1115tv.swizzle_a = p_view.swizzle_a;11161117if (create_shared) {1118texture.driver_id = driver->texture_create_shared(texture.driver_id, tv);1119} else {1120// The regular view will use the same format as the main texture.1121RDD::TextureView regular_view = tv;1122regular_view.format = src_texture->format;1123texture.driver_id = driver->texture_create_shared(texture.driver_id, regular_view);11241125// Create the independent texture for the alias.1126RDD::TextureFormat alias_format = texture.texture_format();1127alias_format.format = tv.format;1128alias_format.usage_bits = TEXTURE_USAGE_SAMPLING_BIT | TEXTURE_USAGE_CAN_COPY_TO_BIT;11291130_texture_check_shared_fallback(src_texture);1131_texture_check_shared_fallback(&texture);11321133texture.shared_fallback->texture = driver->texture_create(alias_format, tv);1134texture.shared_fallback->raw_reinterpretation = raw_reintepretation;1135texture_memory += driver->texture_get_allocation_size(texture.shared_fallback->texture);11361137RDG::ResourceTracker *tracker = RDG::resource_tracker_create();1138tracker->texture_driver_id = texture.shared_fallback->texture;1139tracker->texture_size = Size2i(texture.width, texture.height);1140tracker->texture_subresources = texture.barrier_range();1141tracker->texture_usage = alias_format.usage_bits;1142tracker->is_discardable = texture.is_discardable;1143tracker->reference_count = 1;1144texture.shared_fallback->texture_tracker = tracker;1145texture.shared_fallback->revision = 0;11461147if (raw_reintepretation && src_texture->shared_fallback->buffer.id == 0) {1148// For shared textures of the same size, we create the buffer on the main texture if it doesn't have it already.1149_texture_create_reinterpret_buffer(src_texture);1150}1151}11521153ERR_FAIL_COND_V(!texture.driver_id, RID());11541155if (texture.draw_tracker != nullptr) {1156texture.draw_tracker->reference_count++;1157}11581159texture.owner = p_with_texture;1160RID id = texture_owner.make_rid(texture);1161#ifdef DEV_ENABLED1162set_resource_name(id, "RID:" + itos(id.get_id()));1163#endif1164_add_dependency(id, p_with_texture);11651166return id;1167}11681169RID 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) {1170// This method creates a texture object using a VkImage created by an extension, module or other external source (OpenXR uses this).11711172Texture texture;1173texture.type = p_type;1174texture.format = p_format;1175texture.samples = p_samples;1176texture.width = p_width;1177texture.height = p_height;1178texture.depth = p_depth;1179texture.layers = p_layers;1180texture.mipmaps = p_mipmaps;1181texture.usage_flags = p_usage;1182texture.base_mipmap = 0;1183texture.base_layer = 0;1184texture.allowed_shared_formats.push_back(RD::DATA_FORMAT_R8G8B8A8_UNORM);1185texture.allowed_shared_formats.push_back(RD::DATA_FORMAT_R8G8B8A8_SRGB);11861187if (p_usage.has_flag(TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) {1188texture.read_aspect_flags.set_flag(RDD::TEXTURE_ASPECT_DEPTH_BIT);1189texture.barrier_aspect_flags.set_flag(RDD::TEXTURE_ASPECT_DEPTH_BIT);1190/*if (format_has_stencil(p_format.format)) {1191texture.barrier_aspect_flags.set_flag(RDD::TEXTURE_ASPECT_STENCIL_BIT);1192}*/1193} else {1194texture.read_aspect_flags.set_flag(RDD::TEXTURE_ASPECT_COLOR_BIT);1195texture.barrier_aspect_flags.set_flag(RDD::TEXTURE_ASPECT_COLOR_BIT);1196}11971198texture.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);1199ERR_FAIL_COND_V(!texture.driver_id, RID());12001201_texture_make_mutable(&texture, RID());12021203RID id = texture_owner.make_rid(texture);1204#ifdef DEV_ENABLED1205set_resource_name(id, "RID:" + itos(id.get_id()));1206#endif12071208return id;1209}12101211RID 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) {1212Texture *src_texture = texture_owner.get_or_null(p_with_texture);1213ERR_FAIL_NULL_V(src_texture, RID());12141215if (src_texture->owner.is_valid()) { // // Ahh this is a share. The RenderingDeviceDriver needs the actual owner.1216p_with_texture = src_texture->owner;1217src_texture = texture_owner.get_or_null(src_texture->owner);1218ERR_FAIL_NULL_V(src_texture, RID()); // This is a bug.1219}12201221ERR_FAIL_COND_V_MSG(p_slice_type == TEXTURE_SLICE_CUBEMAP && (src_texture->type != TEXTURE_TYPE_CUBE && src_texture->type != TEXTURE_TYPE_CUBE_ARRAY), RID(),1222"Can only create a cubemap slice from a cubemap or cubemap array mipmap");12231224ERR_FAIL_COND_V_MSG(p_slice_type == TEXTURE_SLICE_3D && src_texture->type != TEXTURE_TYPE_3D, RID(),1225"Can only create a 3D slice from a 3D texture");12261227ERR_FAIL_COND_V_MSG(p_slice_type == TEXTURE_SLICE_2D_ARRAY && (src_texture->type != TEXTURE_TYPE_2D_ARRAY), RID(),1228"Can only create an array slice from a 2D array mipmap");12291230// Create view.12311232ERR_FAIL_UNSIGNED_INDEX_V(p_mipmap, src_texture->mipmaps, RID());1233ERR_FAIL_COND_V(p_mipmap + p_mipmaps > src_texture->mipmaps, RID());1234ERR_FAIL_UNSIGNED_INDEX_V(p_layer, src_texture->layers, RID());12351236int slice_layers = 1;1237if (p_layers != 0) {1238ERR_FAIL_COND_V_MSG(p_layers > 1 && p_slice_type != TEXTURE_SLICE_2D_ARRAY, RID(), "layer slicing only supported for 2D arrays");1239ERR_FAIL_COND_V_MSG(p_layer + p_layers > src_texture->layers, RID(), "layer slice is out of bounds");1240slice_layers = p_layers;1241} else if (p_slice_type == TEXTURE_SLICE_2D_ARRAY) {1242ERR_FAIL_COND_V_MSG(p_layer != 0, RID(), "layer must be 0 when obtaining a 2D array mipmap slice");1243slice_layers = src_texture->layers;1244} else if (p_slice_type == TEXTURE_SLICE_CUBEMAP) {1245slice_layers = 6;1246}12471248Texture texture = *src_texture;1249texture.slice_trackers = nullptr;1250texture.shared_fallback = nullptr;12511252get_image_format_required_size(texture.format, texture.width, texture.height, texture.depth, p_mipmap + 1, &texture.width, &texture.height);1253texture.mipmaps = p_mipmaps;1254texture.layers = slice_layers;1255texture.base_mipmap = p_mipmap;1256texture.base_layer = p_layer;12571258if (p_slice_type == TEXTURE_SLICE_2D) {1259texture.type = TEXTURE_TYPE_2D;1260} else if (p_slice_type == TEXTURE_SLICE_3D) {1261texture.type = TEXTURE_TYPE_3D;1262}12631264RDD::TextureView tv;1265bool create_shared = true;1266bool raw_reintepretation = false;1267if (p_view.format_override == DATA_FORMAT_MAX || p_view.format_override == texture.format) {1268tv.format = texture.format;1269} else {1270ERR_FAIL_INDEX_V(p_view.format_override, DATA_FORMAT_MAX, RID());12711272ERR_FAIL_COND_V_MSG(!texture.allowed_shared_formats.has(p_view.format_override), RID(),1273"Format override is not in the list of allowed shareable formats for original texture.");1274tv.format = p_view.format_override;1275create_shared = driver->texture_can_make_shared_with_format(texture.driver_id, p_view.format_override, raw_reintepretation);1276}12771278tv.swizzle_r = p_view.swizzle_r;1279tv.swizzle_g = p_view.swizzle_g;1280tv.swizzle_b = p_view.swizzle_b;1281tv.swizzle_a = p_view.swizzle_a;12821283if (p_slice_type == TEXTURE_SLICE_CUBEMAP) {1284ERR_FAIL_COND_V_MSG(p_layer >= src_texture->layers, RID(),1285"Specified layer is invalid for cubemap");1286ERR_FAIL_COND_V_MSG((p_layer % 6) != 0, RID(),1287"Specified layer must be a multiple of 6.");1288}12891290if (create_shared) {1291texture.driver_id = driver->texture_create_shared_from_slice(src_texture->driver_id, tv, p_slice_type, p_layer, slice_layers, p_mipmap, p_mipmaps);1292} else {1293// The regular view will use the same format as the main texture.1294RDD::TextureView regular_view = tv;1295regular_view.format = src_texture->format;1296texture.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);12971298// Create the independent texture for the slice.1299RDD::TextureSubresourceRange slice_range = texture.barrier_range();1300slice_range.base_mipmap = 0;1301slice_range.base_layer = 0;13021303RDD::TextureFormat slice_format = texture.texture_format();1304slice_format.width = MAX(texture.width >> p_mipmap, 1U);1305slice_format.height = MAX(texture.height >> p_mipmap, 1U);1306slice_format.depth = MAX(texture.depth >> p_mipmap, 1U);1307slice_format.format = tv.format;1308slice_format.usage_bits = TEXTURE_USAGE_SAMPLING_BIT | TEXTURE_USAGE_CAN_COPY_TO_BIT;13091310_texture_check_shared_fallback(src_texture);1311_texture_check_shared_fallback(&texture);13121313texture.shared_fallback->texture = driver->texture_create(slice_format, tv);1314texture.shared_fallback->raw_reinterpretation = raw_reintepretation;1315texture_memory += driver->texture_get_allocation_size(texture.shared_fallback->texture);13161317RDG::ResourceTracker *tracker = RDG::resource_tracker_create();1318tracker->texture_driver_id = texture.shared_fallback->texture;1319tracker->texture_size = Size2i(texture.width, texture.height);1320tracker->texture_subresources = slice_range;1321tracker->texture_usage = slice_format.usage_bits;1322tracker->is_discardable = slice_format.is_discardable;1323tracker->reference_count = 1;1324texture.shared_fallback->texture_tracker = tracker;1325texture.shared_fallback->revision = 0;13261327if (raw_reintepretation && src_texture->shared_fallback->buffer.id == 0) {1328// For shared texture slices, we create the buffer on the slice if the source texture has no reinterpretation buffer.1329_texture_create_reinterpret_buffer(&texture);1330}1331}13321333ERR_FAIL_COND_V(!texture.driver_id, RID());13341335const Rect2i slice_rect(p_mipmap, p_layer, p_mipmaps, slice_layers);1336texture.owner = p_with_texture;1337texture.slice_type = p_slice_type;1338texture.slice_rect = slice_rect;13391340// If parent is mutable, make slice mutable by default.1341if (src_texture->draw_tracker != nullptr) {1342texture.draw_tracker = nullptr;1343_texture_make_mutable(&texture, RID());1344}13451346RID id = texture_owner.make_rid(texture);1347#ifdef DEV_ENABLED1348set_resource_name(id, "RID:" + itos(id.get_id()));1349#endif1350_add_dependency(id, p_with_texture);13511352return id;1353}13541355static _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) {1356uint32_t src_offset = (p_src_y * p_src_full_w + p_src_x) * p_unit_size;1357uint32_t dst_offset = 0;1358for (uint32_t y = p_src_h; y > 0; y--) {1359uint8_t const *__restrict src = p_src + src_offset;1360uint8_t *__restrict dst = p_dst + dst_offset;1361for (uint32_t x = p_src_w * p_unit_size; x > 0; x--) {1362*dst = *src;1363src++;1364dst++;1365}1366src_offset += p_src_full_w * p_unit_size;1367dst_offset += p_dst_pitch;1368}1369}13701371static _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) {1372if (p_block_w != 1 || p_block_h != 1) {1373// Block format.1374uint32_t xb = p_x / p_block_w;1375uint32_t yb = p_y / p_block_h;1376uint32_t wb = p_width / p_block_w;1377uint32_t region_wb = p_region_w / p_block_w;1378uint32_t region_hb = p_region_h / p_block_h;1379_copy_region(p_read_ptr, p_write_ptr, xb, yb, region_wb, region_hb, wb, p_dst_pitch, p_block_size);1380} else {1381// Regular format.1382_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);1383}1384}13851386uint32_t RenderingDevice::_texture_layer_count(Texture *p_texture) const {1387switch (p_texture->type) {1388case TEXTURE_TYPE_CUBE:1389case TEXTURE_TYPE_CUBE_ARRAY:1390return p_texture->layers * 6;1391default:1392return p_texture->layers;1393}1394}13951396uint32_t greatest_common_denominator(uint32_t a, uint32_t b) {1397// Euclidean algorithm.1398uint32_t t;1399while (b != 0) {1400t = b;1401b = a % b;1402a = t;1403}14041405return a;1406}14071408uint32_t least_common_multiple(uint32_t a, uint32_t b) {1409if (a == 0 || b == 0) {1410return 0;1411}14121413return (a / greatest_common_denominator(a, b)) * b;1414}14151416uint32_t RenderingDevice::_texture_alignment(Texture *p_texture) const {1417uint32_t alignment = get_compressed_image_format_block_byte_size(p_texture->format);1418if (alignment == 1) {1419alignment = get_image_format_pixel_size(p_texture->format);1420}14211422return least_common_multiple(alignment, driver->api_trait_get(RDD::API_TRAIT_TEXTURE_TRANSFER_ALIGNMENT));1423}14241425Error 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) {1426Texture *texture = texture_owner.get_or_null(p_texture);1427ERR_FAIL_NULL_V(texture, ERR_INVALID_PARAMETER);14281429if (texture->owner != RID()) {1430p_texture = texture->owner;1431texture = texture_owner.get_or_null(texture->owner);1432ERR_FAIL_NULL_V(texture, ERR_BUG); // This is a bug.1433}14341435uint32_t layer_count = _texture_layer_count(texture);1436ERR_FAIL_COND_V(p_layer >= layer_count, ERR_INVALID_PARAMETER);14371438uint32_t width, height;1439uint32_t tight_mip_size = get_image_format_required_size(texture->format, texture->width, texture->height, texture->depth, texture->mipmaps, &width, &height);1440uint32_t required_size = tight_mip_size;1441uint32_t required_align = _texture_alignment(texture);14421443ERR_FAIL_COND_V_MSG(required_size != (uint32_t)p_data.size(), ERR_INVALID_PARAMETER,1444"Required size for texture update (" + itos(required_size) + ") does not match data supplied size (" + itos(p_data.size()) + ").");14451446uint32_t block_w, block_h;1447get_compressed_image_format_block_dimensions(texture->format, block_w, block_h);14481449uint32_t pixel_size = get_image_format_pixel_size(texture->format);1450uint32_t pixel_rshift = get_compressed_image_format_pixel_rshift(texture->format);1451uint32_t block_size = get_compressed_image_format_block_byte_size(texture->format);14521453// 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.1454uint32_t staging_worker_offset = 0;1455uint32_t staging_local_offset = 0;1456TransferWorker *transfer_worker = nullptr;1457const uint8_t *read_ptr = p_data.ptr();1458uint8_t *write_ptr = nullptr;1459for (uint32_t pass = 0; pass < 2; pass++) {1460const bool copy_pass = (pass == 1);1461if (copy_pass) {1462transfer_worker = _acquire_transfer_worker(staging_local_offset, required_align, staging_worker_offset);1463texture->transfer_worker_index = transfer_worker->index;14641465{1466MutexLock lock(transfer_worker->operations_mutex);1467texture->transfer_worker_operation = ++transfer_worker->operations_counter;1468}14691470staging_local_offset = 0;14711472write_ptr = driver->buffer_map(transfer_worker->staging_buffer);1473ERR_FAIL_NULL_V(write_ptr, ERR_CANT_CREATE);14741475if (driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) {1476// Transition the texture to the optimal layout.1477RDD::TextureBarrier tb;1478tb.texture = texture->driver_id;1479tb.dst_access = RDD::BARRIER_ACCESS_COPY_WRITE_BIT;1480tb.prev_layout = RDD::TEXTURE_LAYOUT_UNDEFINED;1481tb.next_layout = p_dst_layout;1482tb.subresources.aspect = texture->barrier_aspect_flags;1483tb.subresources.mipmap_count = texture->mipmaps;1484tb.subresources.base_layer = p_layer;1485tb.subresources.layer_count = 1;1486driver->command_pipeline_barrier(transfer_worker->command_buffer, RDD::PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, RDD::PIPELINE_STAGE_COPY_BIT, {}, {}, tb);1487}1488}14891490uint32_t mipmap_offset = 0;1491uint32_t logic_width = texture->width;1492uint32_t logic_height = texture->height;1493for (uint32_t mm_i = 0; mm_i < texture->mipmaps; mm_i++) {1494uint32_t depth = 0;1495uint32_t image_total = get_image_format_required_size(texture->format, texture->width, texture->height, texture->depth, mm_i + 1, &width, &height, &depth);14961497const uint8_t *read_ptr_mipmap = read_ptr + mipmap_offset;1498tight_mip_size = image_total - mipmap_offset;14991500for (uint32_t z = 0; z < depth; z++) {1501if (required_align > 0) {1502uint32_t align_offset = staging_local_offset % required_align;1503if (align_offset != 0) {1504staging_local_offset += required_align - align_offset;1505}1506}15071508uint32_t pitch = (width * pixel_size * block_w) >> pixel_rshift;1509uint32_t pitch_step = driver->api_trait_get(RDD::API_TRAIT_TEXTURE_DATA_ROW_PITCH_STEP);1510pitch = STEPIFY(pitch, pitch_step);1511uint32_t to_allocate = pitch * height;1512to_allocate >>= pixel_rshift;15131514if (copy_pass) {1515const uint8_t *read_ptr_mipmap_layer = read_ptr_mipmap + (tight_mip_size / depth) * z;1516uint64_t staging_buffer_offset = staging_worker_offset + staging_local_offset;1517uint8_t *write_ptr_mipmap_layer = write_ptr + staging_buffer_offset;1518_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);15191520RDD::BufferTextureCopyRegion copy_region;1521copy_region.buffer_offset = staging_buffer_offset;1522copy_region.texture_subresources.aspect = texture->read_aspect_flags;1523copy_region.texture_subresources.mipmap = mm_i;1524copy_region.texture_subresources.base_layer = p_layer;1525copy_region.texture_subresources.layer_count = 1;1526copy_region.texture_offset = Vector3i(0, 0, z);1527copy_region.texture_region_size = Vector3i(logic_width, logic_height, 1);1528driver->command_copy_buffer_to_texture(transfer_worker->command_buffer, transfer_worker->staging_buffer, texture->driver_id, p_dst_layout, copy_region);1529}15301531staging_local_offset += to_allocate;1532}15331534mipmap_offset = image_total;1535logic_width = MAX(1u, logic_width >> 1);1536logic_height = MAX(1u, logic_height >> 1);1537}15381539if (copy_pass) {1540driver->buffer_unmap(transfer_worker->staging_buffer);15411542// If the texture does not have a tracker, it means it must be transitioned to the sampling state.1543if (texture->draw_tracker == nullptr && driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) {1544RDD::TextureBarrier tb;1545tb.texture = texture->driver_id;1546tb.src_access = RDD::BARRIER_ACCESS_COPY_WRITE_BIT;1547tb.prev_layout = p_dst_layout;1548tb.next_layout = RDD::TEXTURE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;1549tb.subresources.aspect = texture->barrier_aspect_flags;1550tb.subresources.mipmap_count = texture->mipmaps;1551tb.subresources.base_layer = p_layer;1552tb.subresources.layer_count = 1;1553transfer_worker->texture_barriers.push_back(tb);1554}15551556if (p_immediate_flush) {1557_end_transfer_worker(transfer_worker);1558_submit_transfer_worker(transfer_worker);1559_wait_for_transfer_worker(transfer_worker);1560}15611562_release_transfer_worker(transfer_worker);1563}1564}15651566return OK;1567}15681569Error RenderingDevice::texture_update(RID p_texture, uint32_t p_layer, const Vector<uint8_t> &p_data) {1570ERR_RENDER_THREAD_GUARD_V(ERR_UNAVAILABLE);15711572ERR_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");15731574Texture *texture = texture_owner.get_or_null(p_texture);1575ERR_FAIL_NULL_V(texture, ERR_INVALID_PARAMETER);15761577if (texture->owner != RID()) {1578p_texture = texture->owner;1579texture = texture_owner.get_or_null(texture->owner);1580ERR_FAIL_NULL_V(texture, ERR_BUG); // This is a bug.1581}15821583ERR_FAIL_COND_V_MSG(texture->bound, ERR_CANT_ACQUIRE_RESOURCE,1584"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.");15851586ERR_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.");15871588uint32_t layer_count = _texture_layer_count(texture);1589ERR_FAIL_COND_V(p_layer >= layer_count, ERR_INVALID_PARAMETER);15901591uint32_t width, height;1592uint32_t tight_mip_size = get_image_format_required_size(texture->format, texture->width, texture->height, texture->depth, texture->mipmaps, &width, &height);1593uint32_t required_size = tight_mip_size;1594uint32_t required_align = _texture_alignment(texture);15951596ERR_FAIL_COND_V_MSG(required_size != (uint32_t)p_data.size(), ERR_INVALID_PARAMETER,1597"Required size for texture update (" + itos(required_size) + ") does not match data supplied size (" + itos(p_data.size()) + ").");15981599_check_transfer_worker_texture(texture);16001601uint32_t block_w, block_h;1602get_compressed_image_format_block_dimensions(texture->format, block_w, block_h);16031604uint32_t pixel_size = get_image_format_pixel_size(texture->format);1605uint32_t pixel_rshift = get_compressed_image_format_pixel_rshift(texture->format);1606uint32_t block_size = get_compressed_image_format_block_byte_size(texture->format);16071608uint32_t region_size = texture_upload_region_size_px;16091610const uint8_t *read_ptr = p_data.ptr();16111612thread_local LocalVector<RDG::RecordedBufferToTextureCopy> command_buffer_to_texture_copies_vector;1613command_buffer_to_texture_copies_vector.clear();16141615// Indicate the texture will get modified for the shared texture fallback.1616_texture_update_shared_fallback(p_texture, texture, true);16171618uint32_t mipmap_offset = 0;16191620uint32_t logic_width = texture->width;1621uint32_t logic_height = texture->height;16221623for (uint32_t mm_i = 0; mm_i < texture->mipmaps; mm_i++) {1624uint32_t depth = 0;1625uint32_t image_total = get_image_format_required_size(texture->format, texture->width, texture->height, texture->depth, mm_i + 1, &width, &height, &depth);16261627const uint8_t *read_ptr_mipmap = read_ptr + mipmap_offset;1628tight_mip_size = image_total - mipmap_offset;16291630for (uint32_t z = 0; z < depth; z++) {1631const uint8_t *read_ptr_mipmap_layer = read_ptr_mipmap + (tight_mip_size / depth) * z;1632for (uint32_t y = 0; y < height; y += region_size) {1633for (uint32_t x = 0; x < width; x += region_size) {1634uint32_t region_w = MIN(region_size, width - x);1635uint32_t region_h = MIN(region_size, height - y);16361637uint32_t region_logic_w = MIN(region_size, logic_width - x);1638uint32_t region_logic_h = MIN(region_size, logic_height - y);16391640uint32_t region_pitch = (region_w * pixel_size * block_w) >> pixel_rshift;1641uint32_t pitch_step = driver->api_trait_get(RDD::API_TRAIT_TEXTURE_DATA_ROW_PITCH_STEP);1642region_pitch = STEPIFY(region_pitch, pitch_step);1643uint32_t to_allocate = region_pitch * region_h;1644uint32_t alloc_offset = 0, alloc_size = 0;1645StagingRequiredAction required_action;1646Error err = _staging_buffer_allocate(upload_staging_buffers, to_allocate, required_align, alloc_offset, alloc_size, required_action, false);1647ERR_FAIL_COND_V(err, ERR_CANT_CREATE);16481649if (!command_buffer_to_texture_copies_vector.is_empty() && required_action == STAGING_REQUIRED_ACTION_FLUSH_AND_STALL_ALL) {1650if (_texture_make_mutable(texture, p_texture)) {1651// The texture must be mutable to be used as a copy destination.1652draw_graph.add_synchronization();1653}16541655// If the staging buffer requires flushing everything, we submit the command early and clear the current vector.1656draw_graph.add_texture_update(texture->driver_id, texture->draw_tracker, command_buffer_to_texture_copies_vector);1657command_buffer_to_texture_copies_vector.clear();1658}16591660_staging_buffer_execute_required_action(upload_staging_buffers, required_action);16611662uint8_t *write_ptr;16631664{ // Map.1665uint8_t *data_ptr = driver->buffer_map(upload_staging_buffers.blocks[upload_staging_buffers.current].driver_id);1666ERR_FAIL_NULL_V(data_ptr, ERR_CANT_CREATE);1667write_ptr = data_ptr;1668write_ptr += alloc_offset;1669}16701671ERR_FAIL_COND_V(region_w % block_w, ERR_BUG);1672ERR_FAIL_COND_V(region_h % block_h, ERR_BUG);16731674_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);16751676{ // Unmap.1677driver->buffer_unmap(upload_staging_buffers.blocks[upload_staging_buffers.current].driver_id);1678}16791680RDD::BufferTextureCopyRegion copy_region;1681copy_region.buffer_offset = alloc_offset;1682copy_region.texture_subresources.aspect = texture->read_aspect_flags;1683copy_region.texture_subresources.mipmap = mm_i;1684copy_region.texture_subresources.base_layer = p_layer;1685copy_region.texture_subresources.layer_count = 1;1686copy_region.texture_offset = Vector3i(x, y, z);1687copy_region.texture_region_size = Vector3i(region_logic_w, region_logic_h, 1);16881689RDG::RecordedBufferToTextureCopy buffer_to_texture_copy;1690buffer_to_texture_copy.from_buffer = upload_staging_buffers.blocks[upload_staging_buffers.current].driver_id;1691buffer_to_texture_copy.region = copy_region;1692command_buffer_to_texture_copies_vector.push_back(buffer_to_texture_copy);16931694upload_staging_buffers.blocks.write[upload_staging_buffers.current].fill_amount = alloc_offset + alloc_size;1695}1696}1697}16981699mipmap_offset = image_total;1700logic_width = MAX(1u, logic_width >> 1);1701logic_height = MAX(1u, logic_height >> 1);1702}17031704if (_texture_make_mutable(texture, p_texture)) {1705// The texture must be mutable to be used as a copy destination.1706draw_graph.add_synchronization();1707}17081709draw_graph.add_texture_update(texture->driver_id, texture->draw_tracker, command_buffer_to_texture_copies_vector);17101711return OK;1712}17131714void RenderingDevice::_texture_check_shared_fallback(Texture *p_texture) {1715if (p_texture->shared_fallback == nullptr) {1716p_texture->shared_fallback = memnew(Texture::SharedFallback);1717}1718}17191720void RenderingDevice::_texture_update_shared_fallback(RID p_texture_rid, Texture *p_texture, bool p_for_writing) {1721if (p_texture->shared_fallback == nullptr) {1722// This texture does not use any of the shared texture fallbacks.1723return;1724}17251726if (p_texture->owner.is_valid()) {1727Texture *owner_texture = texture_owner.get_or_null(p_texture->owner);1728ERR_FAIL_NULL(owner_texture);1729if (p_for_writing) {1730// Only the main texture is used for writing when using the shared fallback.1731owner_texture->shared_fallback->revision++;1732} else if (p_texture->shared_fallback->revision != owner_texture->shared_fallback->revision) {1733// Copy the contents of the main texture into the shared texture fallback slice. Update the revision.1734_texture_copy_shared(p_texture->owner, owner_texture, p_texture_rid, p_texture);1735p_texture->shared_fallback->revision = owner_texture->shared_fallback->revision;1736}1737} else if (p_for_writing) {1738// Increment the revision of the texture so shared texture fallback slices must be updated.1739p_texture->shared_fallback->revision++;1740}1741}17421743void RenderingDevice::_texture_free_shared_fallback(Texture *p_texture) {1744if (p_texture->shared_fallback != nullptr) {1745if (p_texture->shared_fallback->texture_tracker != nullptr) {1746RDG::resource_tracker_free(p_texture->shared_fallback->texture_tracker);1747}17481749if (p_texture->shared_fallback->buffer_tracker != nullptr) {1750RDG::resource_tracker_free(p_texture->shared_fallback->buffer_tracker);1751}17521753if (p_texture->shared_fallback->texture.id != 0) {1754texture_memory -= driver->texture_get_allocation_size(p_texture->shared_fallback->texture);1755driver->texture_free(p_texture->shared_fallback->texture);1756}17571758if (p_texture->shared_fallback->buffer.id != 0) {1759buffer_memory -= driver->buffer_get_allocation_size(p_texture->shared_fallback->buffer);1760driver->buffer_free(p_texture->shared_fallback->buffer);1761}17621763memdelete(p_texture->shared_fallback);1764p_texture->shared_fallback = nullptr;1765}1766}17671768void RenderingDevice::_texture_copy_shared(RID p_src_texture_rid, Texture *p_src_texture, RID p_dst_texture_rid, Texture *p_dst_texture) {1769// 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.1770DEV_ASSERT(p_src_texture != nullptr);1771DEV_ASSERT(p_dst_texture != nullptr);1772DEV_ASSERT(p_src_texture->owner.is_null());1773DEV_ASSERT(p_dst_texture->owner == p_src_texture_rid);17741775bool src_made_mutable = _texture_make_mutable(p_src_texture, p_src_texture_rid);1776bool dst_made_mutable = _texture_make_mutable(p_dst_texture, p_dst_texture_rid);1777if (src_made_mutable || dst_made_mutable) {1778draw_graph.add_synchronization();1779}17801781if (p_dst_texture->shared_fallback->raw_reinterpretation) {1782// 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 hold1783// anything and it's how the shared textures that don't use slices are created.1784bool src_has_buffer = p_src_texture->shared_fallback->buffer.id != 0;1785bool dst_has_buffer = p_dst_texture->shared_fallback->buffer.id != 0;1786bool from_src = p_src_texture->owner.is_null() && src_has_buffer;1787bool from_dst = p_dst_texture->owner.is_null() && dst_has_buffer;1788if (!from_src && !from_dst) {1789// If neither texture passed the condition, we just pick whichever texture has a reinterpretation buffer.1790from_src = src_has_buffer;1791from_dst = dst_has_buffer;1792}17931794// Pick the buffer and tracker to use from the right texture.1795RDD::BufferID shared_buffer;1796RDG::ResourceTracker *shared_buffer_tracker = nullptr;1797if (from_src) {1798shared_buffer = p_src_texture->shared_fallback->buffer;1799shared_buffer_tracker = p_src_texture->shared_fallback->buffer_tracker;1800} else if (from_dst) {1801shared_buffer = p_dst_texture->shared_fallback->buffer;1802shared_buffer_tracker = p_dst_texture->shared_fallback->buffer_tracker;1803} else {1804DEV_ASSERT(false && "This path should not be reachable.");1805}18061807// FIXME: When using reinterpretation buffers, the only texture aspect supported is color. Depth or stencil contents won't get copied.1808RDD::BufferTextureCopyRegion get_data_region;1809RDG::RecordedBufferToTextureCopy update_copy;1810RDD::TextureCopyableLayout first_copyable_layout;1811RDD::TextureCopyableLayout copyable_layout;1812RDD::TextureSubresource texture_subresource;1813texture_subresource.aspect = RDD::TEXTURE_ASPECT_COLOR;1814texture_subresource.layer = 0;1815texture_subresource.mipmap = 0;1816driver->texture_get_copyable_layout(p_dst_texture->shared_fallback->texture, texture_subresource, &first_copyable_layout);18171818// Copying each mipmap from main texture to a buffer and then to the slice texture.1819thread_local LocalVector<RDD::BufferTextureCopyRegion> get_data_vector;1820thread_local LocalVector<RDG::RecordedBufferToTextureCopy> update_vector;1821get_data_vector.clear();1822update_vector.clear();1823for (uint32_t i = 0; i < p_dst_texture->mipmaps; i++) {1824driver->texture_get_copyable_layout(p_dst_texture->shared_fallback->texture, texture_subresource, ©able_layout);18251826uint32_t mipmap = p_dst_texture->base_mipmap + i;1827get_data_region.buffer_offset = copyable_layout.offset - first_copyable_layout.offset;1828get_data_region.texture_subresources.aspect = RDD::TEXTURE_ASPECT_COLOR_BIT;1829get_data_region.texture_subresources.base_layer = p_dst_texture->base_layer;1830get_data_region.texture_subresources.mipmap = mipmap;1831get_data_region.texture_subresources.layer_count = p_dst_texture->layers;1832get_data_region.texture_region_size.x = MAX(1U, p_src_texture->width >> mipmap);1833get_data_region.texture_region_size.y = MAX(1U, p_src_texture->height >> mipmap);1834get_data_region.texture_region_size.z = MAX(1U, p_src_texture->depth >> mipmap);1835get_data_vector.push_back(get_data_region);18361837update_copy.from_buffer = shared_buffer;1838update_copy.region.buffer_offset = get_data_region.buffer_offset;1839update_copy.region.texture_subresources.aspect = RDD::TEXTURE_ASPECT_COLOR_BIT;1840update_copy.region.texture_subresources.base_layer = texture_subresource.layer;1841update_copy.region.texture_subresources.mipmap = texture_subresource.mipmap;1842update_copy.region.texture_subresources.layer_count = get_data_region.texture_subresources.layer_count;1843update_copy.region.texture_region_size.x = get_data_region.texture_region_size.x;1844update_copy.region.texture_region_size.y = get_data_region.texture_region_size.y;1845update_copy.region.texture_region_size.z = get_data_region.texture_region_size.z;1846update_vector.push_back(update_copy);18471848texture_subresource.mipmap++;1849}18501851draw_graph.add_texture_get_data(p_src_texture->driver_id, p_src_texture->draw_tracker, shared_buffer, get_data_vector, shared_buffer_tracker);1852draw_graph.add_texture_update(p_dst_texture->shared_fallback->texture, p_dst_texture->shared_fallback->texture_tracker, update_vector, shared_buffer_tracker);1853} else {1854// Raw reinterpretation is not required. Use a regular texture copy.1855RDD::TextureCopyRegion copy_region;1856copy_region.src_subresources.aspect = p_src_texture->read_aspect_flags;1857copy_region.src_subresources.base_layer = p_dst_texture->base_layer;1858copy_region.src_subresources.layer_count = p_dst_texture->layers;1859copy_region.dst_subresources.aspect = p_dst_texture->read_aspect_flags;1860copy_region.dst_subresources.base_layer = 0;1861copy_region.dst_subresources.layer_count = copy_region.src_subresources.layer_count;18621863// Copying each mipmap from main texture to to the slice texture.1864thread_local LocalVector<RDD::TextureCopyRegion> region_vector;1865region_vector.clear();1866for (uint32_t i = 0; i < p_dst_texture->mipmaps; i++) {1867uint32_t mipmap = p_dst_texture->base_mipmap + i;1868copy_region.src_subresources.mipmap = mipmap;1869copy_region.dst_subresources.mipmap = i;1870copy_region.size.x = MAX(1U, p_src_texture->width >> mipmap);1871copy_region.size.y = MAX(1U, p_src_texture->height >> mipmap);1872copy_region.size.z = MAX(1U, p_src_texture->depth >> mipmap);1873region_vector.push_back(copy_region);1874}18751876draw_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);1877}1878}18791880void RenderingDevice::_texture_create_reinterpret_buffer(Texture *p_texture) {1881uint64_t row_pitch_step = driver->api_trait_get(RDD::API_TRAIT_TEXTURE_DATA_ROW_PITCH_STEP);1882uint64_t transfer_alignment = driver->api_trait_get(RDD::API_TRAIT_TEXTURE_TRANSFER_ALIGNMENT);1883uint32_t pixel_bytes = get_image_format_pixel_size(p_texture->format);1884uint32_t row_pitch = STEPIFY(p_texture->width * pixel_bytes, row_pitch_step);1885uint64_t buffer_size = STEPIFY(pixel_bytes * row_pitch * p_texture->height * p_texture->depth, transfer_alignment);1886p_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);1887buffer_memory += driver->buffer_get_allocation_size(p_texture->shared_fallback->buffer);18881889RDG::ResourceTracker *tracker = RDG::resource_tracker_create();1890tracker->buffer_driver_id = p_texture->shared_fallback->buffer;1891p_texture->shared_fallback->buffer_tracker = tracker;1892}18931894uint32_t RenderingDevice::_texture_vrs_method_to_usage_bits() const {1895switch (vrs_method) {1896case VRS_METHOD_FRAGMENT_SHADING_RATE:1897return RDD::TEXTURE_USAGE_VRS_FRAGMENT_SHADING_RATE_BIT;1898case VRS_METHOD_FRAGMENT_DENSITY_MAP:1899return RDD::TEXTURE_USAGE_VRS_FRAGMENT_DENSITY_MAP_BIT;1900default:1901return 0;1902}1903}19041905Vector<uint8_t> RenderingDevice::_texture_get_data(Texture *tex, uint32_t p_layer, bool p_2d) {1906uint32_t width, height, depth;1907uint32_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);19081909Vector<uint8_t> image_data;1910image_data.resize(tight_mip_size);19111912uint32_t blockw, blockh;1913get_compressed_image_format_block_dimensions(tex->format, blockw, blockh);1914uint32_t block_size = get_compressed_image_format_block_byte_size(tex->format);1915uint32_t pixel_size = get_image_format_pixel_size(tex->format);19161917{1918uint8_t *w = image_data.ptrw();19191920uint32_t mipmap_offset = 0;1921for (uint32_t mm_i = 0; mm_i < tex->mipmaps; mm_i++) {1922uint32_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);19231924uint8_t *write_ptr_mipmap = w + mipmap_offset;1925tight_mip_size = image_total - mipmap_offset;19261927RDD::TextureSubresource subres;1928subres.aspect = RDD::TEXTURE_ASPECT_COLOR;1929subres.layer = p_layer;1930subres.mipmap = mm_i;1931RDD::TextureCopyableLayout layout;1932driver->texture_get_copyable_layout(tex->driver_id, subres, &layout);19331934uint8_t *img_mem = driver->texture_map(tex->driver_id, subres);1935ERR_FAIL_NULL_V(img_mem, Vector<uint8_t>());19361937for (uint32_t z = 0; z < depth; z++) {1938uint8_t *write_ptr = write_ptr_mipmap + z * tight_mip_size / depth;1939const uint8_t *slice_read_ptr = img_mem + z * layout.depth_pitch;19401941if (block_size > 1) {1942// Compressed.1943uint32_t line_width = (block_size * (width / blockw));1944for (uint32_t y = 0; y < height / blockh; y++) {1945const uint8_t *rptr = slice_read_ptr + y * layout.row_pitch;1946uint8_t *wptr = write_ptr + y * line_width;19471948memcpy(wptr, rptr, line_width);1949}19501951} else {1952// Uncompressed.1953for (uint32_t y = 0; y < height; y++) {1954const uint8_t *rptr = slice_read_ptr + y * layout.row_pitch;1955uint8_t *wptr = write_ptr + y * pixel_size * width;1956memcpy(wptr, rptr, (uint64_t)pixel_size * width);1957}1958}1959}19601961driver->texture_unmap(tex->driver_id);19621963mipmap_offset = image_total;1964}1965}19661967return image_data;1968}19691970Vector<uint8_t> RenderingDevice::texture_get_data(RID p_texture, uint32_t p_layer) {1971ERR_RENDER_THREAD_GUARD_V(Vector<uint8_t>());19721973Texture *tex = texture_owner.get_or_null(p_texture);1974ERR_FAIL_NULL_V(tex, Vector<uint8_t>());19751976ERR_FAIL_COND_V_MSG(tex->bound, Vector<uint8_t>(),1977"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.");1978ERR_FAIL_COND_V_MSG(!(tex->usage_flags & TEXTURE_USAGE_CAN_COPY_FROM_BIT), Vector<uint8_t>(),1979"Texture requires the `RenderingDevice.TEXTURE_USAGE_CAN_COPY_FROM_BIT` to be set to be retrieved.");19801981ERR_FAIL_COND_V(p_layer >= tex->layers, Vector<uint8_t>());19821983_check_transfer_worker_texture(tex);19841985if (tex->usage_flags & TEXTURE_USAGE_CPU_READ_BIT) {1986// Does not need anything fancy, map and read.1987return _texture_get_data(tex, p_layer);1988} else {1989LocalVector<RDD::TextureCopyableLayout> mip_layouts;1990uint32_t work_mip_alignment = driver->api_trait_get(RDD::API_TRAIT_TEXTURE_TRANSFER_ALIGNMENT);1991uint32_t work_buffer_size = 0;1992mip_layouts.resize(tex->mipmaps);1993for (uint32_t i = 0; i < tex->mipmaps; i++) {1994RDD::TextureSubresource subres;1995subres.aspect = RDD::TEXTURE_ASPECT_COLOR;1996subres.layer = p_layer;1997subres.mipmap = i;1998driver->texture_get_copyable_layout(tex->driver_id, subres, &mip_layouts[i]);19992000// Assuming layers are tightly packed. If this is not true on some driver, we must modify the copy algorithm.2001DEV_ASSERT(mip_layouts[i].layer_pitch == mip_layouts[i].size / tex->layers);20022003work_buffer_size = STEPIFY(work_buffer_size, work_mip_alignment) + mip_layouts[i].size;2004}20052006RDD::BufferID tmp_buffer = driver->buffer_create(work_buffer_size, RDD::BUFFER_USAGE_TRANSFER_TO_BIT, RDD::MEMORY_ALLOCATION_TYPE_CPU);2007ERR_FAIL_COND_V(!tmp_buffer, Vector<uint8_t>());20082009thread_local LocalVector<RDD::BufferTextureCopyRegion> command_buffer_texture_copy_regions_vector;2010command_buffer_texture_copy_regions_vector.clear();20112012uint32_t w = tex->width;2013uint32_t h = tex->height;2014uint32_t d = tex->depth;2015for (uint32_t i = 0; i < tex->mipmaps; i++) {2016RDD::BufferTextureCopyRegion copy_region;2017copy_region.buffer_offset = mip_layouts[i].offset;2018copy_region.texture_subresources.aspect = tex->read_aspect_flags;2019copy_region.texture_subresources.mipmap = i;2020copy_region.texture_subresources.base_layer = p_layer;2021copy_region.texture_subresources.layer_count = 1;2022copy_region.texture_region_size.x = w;2023copy_region.texture_region_size.y = h;2024copy_region.texture_region_size.z = d;2025command_buffer_texture_copy_regions_vector.push_back(copy_region);20262027w = MAX(1u, w >> 1);2028h = MAX(1u, h >> 1);2029d = MAX(1u, d >> 1);2030}20312032if (_texture_make_mutable(tex, p_texture)) {2033// The texture must be mutable to be used as a copy source due to layout transitions.2034draw_graph.add_synchronization();2035}20362037draw_graph.add_texture_get_data(tex->driver_id, tex->draw_tracker, tmp_buffer, command_buffer_texture_copy_regions_vector);20382039// Flush everything so memory can be safely mapped.2040_flush_and_stall_for_all_frames();20412042const uint8_t *read_ptr = driver->buffer_map(tmp_buffer);2043ERR_FAIL_NULL_V(read_ptr, Vector<uint8_t>());20442045uint32_t block_w = 0;2046uint32_t block_h = 0;2047get_compressed_image_format_block_dimensions(tex->format, block_w, block_h);20482049Vector<uint8_t> buffer_data;2050uint32_t tight_buffer_size = get_image_format_required_size(tex->format, tex->width, tex->height, tex->depth, tex->mipmaps);2051buffer_data.resize(tight_buffer_size);20522053uint8_t *write_ptr = buffer_data.ptrw();20542055w = tex->width;2056h = tex->height;2057d = tex->depth;2058for (uint32_t i = 0; i < tex->mipmaps; i++) {2059uint32_t width = 0, height = 0, depth = 0;2060uint32_t tight_mip_size = get_image_format_required_size(tex->format, w, h, d, 1, &width, &height, &depth);2061uint32_t tight_row_pitch = tight_mip_size / ((height / block_h) * depth);20622063// Copy row-by-row to erase padding due to alignments.2064const uint8_t *rp = read_ptr;2065uint8_t *wp = write_ptr;2066for (uint32_t row = h * d / block_h; row != 0; row--) {2067memcpy(wp, rp, tight_row_pitch);2068rp += mip_layouts[i].row_pitch;2069wp += tight_row_pitch;2070}20712072w = MAX(block_w, w >> 1);2073h = MAX(block_h, h >> 1);2074d = MAX(1u, d >> 1);2075read_ptr += mip_layouts[i].size;2076write_ptr += tight_mip_size;2077}20782079driver->buffer_unmap(tmp_buffer);2080driver->buffer_free(tmp_buffer);20812082return buffer_data;2083}2084}20852086Error RenderingDevice::texture_get_data_async(RID p_texture, uint32_t p_layer, const Callable &p_callback) {2087ERR_RENDER_THREAD_GUARD_V(ERR_UNAVAILABLE);20882089Texture *tex = texture_owner.get_or_null(p_texture);2090ERR_FAIL_NULL_V(tex, ERR_INVALID_PARAMETER);20912092ERR_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.");2093ERR_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.");2094ERR_FAIL_COND_V(p_layer >= tex->layers, ERR_INVALID_PARAMETER);20952096_check_transfer_worker_texture(tex);20972098thread_local LocalVector<RDD::TextureCopyableLayout> mip_layouts;2099mip_layouts.resize(tex->mipmaps);2100for (uint32_t i = 0; i < tex->mipmaps; i++) {2101RDD::TextureSubresource subres;2102subres.aspect = RDD::TEXTURE_ASPECT_COLOR;2103subres.layer = p_layer;2104subres.mipmap = i;2105driver->texture_get_copyable_layout(tex->driver_id, subres, &mip_layouts[i]);21062107// Assuming layers are tightly packed. If this is not true on some driver, we must modify the copy algorithm.2108DEV_ASSERT(mip_layouts[i].layer_pitch == mip_layouts[i].size / tex->layers);2109}21102111ERR_FAIL_COND_V(mip_layouts.is_empty(), ERR_INVALID_PARAMETER);21122113if (_texture_make_mutable(tex, p_texture)) {2114// The texture must be mutable to be used as a copy source due to layout transitions.2115draw_graph.add_synchronization();2116}21172118TextureGetDataRequest get_data_request;2119get_data_request.callback = p_callback;2120get_data_request.frame_local_index = frames[frame].download_buffer_texture_copy_regions.size();2121get_data_request.width = tex->width;2122get_data_request.height = tex->height;2123get_data_request.depth = tex->depth;2124get_data_request.format = tex->format;2125get_data_request.mipmaps = tex->mipmaps;21262127uint32_t block_w, block_h;2128get_compressed_image_format_block_dimensions(tex->format, block_w, block_h);21292130uint32_t pixel_size = get_image_format_pixel_size(tex->format);2131uint32_t pixel_rshift = get_compressed_image_format_pixel_rshift(tex->format);21322133uint32_t w, h, d;2134uint32_t required_align = driver->api_trait_get(RDD::API_TRAIT_TEXTURE_TRANSFER_ALIGNMENT);2135uint32_t pitch_step = driver->api_trait_get(RDD::API_TRAIT_TEXTURE_DATA_ROW_PITCH_STEP);2136uint32_t region_size = texture_download_region_size_px;2137uint32_t logic_w = tex->width;2138uint32_t logic_h = tex->height;2139uint32_t mipmap_offset = 0;2140uint32_t block_write_offset;2141uint32_t block_write_amount;2142StagingRequiredAction required_action;2143for (uint32_t i = 0; i < tex->mipmaps; i++) {2144uint32_t image_total = get_image_format_required_size(tex->format, tex->width, tex->height, tex->depth, i + 1, &w, &h, &d);2145uint32_t tight_mip_size = image_total - mipmap_offset;2146for (uint32_t z = 0; z < d; z++) {2147for (uint32_t y = 0; y < h; y += region_size) {2148for (uint32_t x = 0; x < w; x += region_size) {2149uint32_t region_w = MIN(region_size, w - x);2150uint32_t region_h = MIN(region_size, h - y);2151ERR_FAIL_COND_V(region_w % block_w, ERR_BUG);2152ERR_FAIL_COND_V(region_h % block_h, ERR_BUG);21532154uint32_t region_logic_w = MIN(region_size, logic_w - x);2155uint32_t region_logic_h = MIN(region_size, logic_h - y);2156uint32_t region_pitch = (region_w * pixel_size * block_w) >> pixel_rshift;2157region_pitch = STEPIFY(region_pitch, pitch_step);21582159uint32_t to_allocate = region_pitch * region_h;2160Error err = _staging_buffer_allocate(download_staging_buffers, to_allocate, required_align, block_write_offset, block_write_amount, required_action, false);2161ERR_FAIL_COND_V(err, ERR_CANT_CREATE);21622163const bool flush_frames = (get_data_request.frame_local_count > 0) && required_action == STAGING_REQUIRED_ACTION_FLUSH_AND_STALL_ALL;2164if (flush_frames) {2165for (uint32_t j = 0; j < get_data_request.frame_local_count; j++) {2166uint32_t local_index = get_data_request.frame_local_index + j;2167draw_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]);2168}2169}21702171_staging_buffer_execute_required_action(download_staging_buffers, required_action);21722173if (flush_frames) {2174get_data_request.frame_local_count = 0;2175get_data_request.frame_local_index = frames[frame].download_buffer_texture_copy_regions.size();2176}21772178RDD::BufferTextureCopyRegion copy_region;2179copy_region.buffer_offset = block_write_offset;2180copy_region.texture_subresources.aspect = tex->read_aspect_flags;2181copy_region.texture_subresources.mipmap = i;2182copy_region.texture_subresources.base_layer = p_layer;2183copy_region.texture_subresources.layer_count = 1;2184copy_region.texture_offset = Vector3i(x, y, z);2185copy_region.texture_region_size = Vector3i(region_logic_w, region_logic_h, 1);2186frames[frame].download_texture_staging_buffers.push_back(download_staging_buffers.blocks[download_staging_buffers.current].driver_id);2187frames[frame].download_buffer_texture_copy_regions.push_back(copy_region);2188frames[frame].download_texture_mipmap_offsets.push_back(mipmap_offset + (tight_mip_size / d) * z);2189get_data_request.frame_local_count++;21902191download_staging_buffers.blocks.write[download_staging_buffers.current].fill_amount = block_write_offset + block_write_amount;2192}2193}2194}21952196mipmap_offset = image_total;2197logic_w = MAX(1u, logic_w >> 1);2198logic_h = MAX(1u, logic_h >> 1);2199}22002201if (get_data_request.frame_local_count > 0) {2202for (uint32_t i = 0; i < get_data_request.frame_local_count; i++) {2203uint32_t local_index = get_data_request.frame_local_index + i;2204draw_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]);2205}22062207frames[frame].download_texture_get_data_requests.push_back(get_data_request);2208}22092210return OK;2211}22122213bool RenderingDevice::texture_is_shared(RID p_texture) {2214ERR_RENDER_THREAD_GUARD_V(false);22152216Texture *tex = texture_owner.get_or_null(p_texture);2217ERR_FAIL_NULL_V(tex, false);2218return tex->owner.is_valid();2219}22202221bool RenderingDevice::texture_is_valid(RID p_texture) {2222ERR_RENDER_THREAD_GUARD_V(false);22232224return texture_owner.owns(p_texture);2225}22262227RD::TextureFormat RenderingDevice::texture_get_format(RID p_texture) {2228ERR_RENDER_THREAD_GUARD_V(TextureFormat());22292230Texture *tex = texture_owner.get_or_null(p_texture);2231ERR_FAIL_NULL_V(tex, TextureFormat());22322233TextureFormat tf;22342235tf.format = tex->format;2236tf.width = tex->width;2237tf.height = tex->height;2238tf.depth = tex->depth;2239tf.array_layers = tex->layers;2240tf.mipmaps = tex->mipmaps;2241tf.texture_type = tex->type;2242tf.samples = tex->samples;2243tf.usage_bits = tex->usage_flags;2244tf.shareable_formats = tex->allowed_shared_formats;2245tf.is_resolve_buffer = tex->is_resolve_buffer;2246tf.is_discardable = tex->is_discardable;22472248return tf;2249}22502251Size2i RenderingDevice::texture_size(RID p_texture) {2252ERR_RENDER_THREAD_GUARD_V(Size2i());22532254Texture *tex = texture_owner.get_or_null(p_texture);2255ERR_FAIL_NULL_V(tex, Size2i());2256return Size2i(tex->width, tex->height);2257}22582259#ifndef DISABLE_DEPRECATED2260uint64_t RenderingDevice::texture_get_native_handle(RID p_texture) {2261return get_driver_resource(DRIVER_RESOURCE_TEXTURE, p_texture);2262}2263#endif22642265Error 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) {2266ERR_RENDER_THREAD_GUARD_V(ERR_UNAVAILABLE);22672268Texture *src_tex = texture_owner.get_or_null(p_from_texture);2269ERR_FAIL_NULL_V(src_tex, ERR_INVALID_PARAMETER);22702271ERR_FAIL_COND_V_MSG(src_tex->bound, ERR_INVALID_PARAMETER,2272"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.");2273ERR_FAIL_COND_V_MSG(!(src_tex->usage_flags & TEXTURE_USAGE_CAN_COPY_FROM_BIT), ERR_INVALID_PARAMETER,2274"Source texture requires the `RenderingDevice.TEXTURE_USAGE_CAN_COPY_FROM_BIT` to be set to be retrieved.");22752276uint32_t src_width, src_height, src_depth;2277get_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);22782279ERR_FAIL_COND_V(p_from.x < 0 || p_from.x + p_size.x > src_width, ERR_INVALID_PARAMETER);2280ERR_FAIL_COND_V(p_from.y < 0 || p_from.y + p_size.y > src_height, ERR_INVALID_PARAMETER);2281ERR_FAIL_COND_V(p_from.z < 0 || p_from.z + p_size.z > src_depth, ERR_INVALID_PARAMETER);2282ERR_FAIL_COND_V(p_src_mipmap >= src_tex->mipmaps, ERR_INVALID_PARAMETER);2283ERR_FAIL_COND_V(p_src_layer >= src_tex->layers, ERR_INVALID_PARAMETER);22842285Texture *dst_tex = texture_owner.get_or_null(p_to_texture);2286ERR_FAIL_NULL_V(dst_tex, ERR_INVALID_PARAMETER);22872288ERR_FAIL_COND_V_MSG(dst_tex->bound, ERR_INVALID_PARAMETER,2289"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.");2290ERR_FAIL_COND_V_MSG(!(dst_tex->usage_flags & TEXTURE_USAGE_CAN_COPY_TO_BIT), ERR_INVALID_PARAMETER,2291"Destination texture requires the `RenderingDevice.TEXTURE_USAGE_CAN_COPY_TO_BIT` to be set to be retrieved.");22922293uint32_t dst_width, dst_height, dst_depth;2294get_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);22952296ERR_FAIL_COND_V(p_to.x < 0 || p_to.x + p_size.x > dst_width, ERR_INVALID_PARAMETER);2297ERR_FAIL_COND_V(p_to.y < 0 || p_to.y + p_size.y > dst_height, ERR_INVALID_PARAMETER);2298ERR_FAIL_COND_V(p_to.z < 0 || p_to.z + p_size.z > dst_depth, ERR_INVALID_PARAMETER);2299ERR_FAIL_COND_V(p_dst_mipmap >= dst_tex->mipmaps, ERR_INVALID_PARAMETER);2300ERR_FAIL_COND_V(p_dst_layer >= dst_tex->layers, ERR_INVALID_PARAMETER);23012302ERR_FAIL_COND_V_MSG(src_tex->read_aspect_flags != dst_tex->read_aspect_flags, ERR_INVALID_PARAMETER,2303"Source and destination texture must be of the same type (color or depth).");23042305_check_transfer_worker_texture(src_tex);2306_check_transfer_worker_texture(dst_tex);23072308RDD::TextureCopyRegion copy_region;2309copy_region.src_subresources.aspect = src_tex->read_aspect_flags;2310copy_region.src_subresources.mipmap = p_src_mipmap;2311copy_region.src_subresources.base_layer = p_src_layer;2312copy_region.src_subresources.layer_count = 1;2313copy_region.src_offset = p_from;23142315copy_region.dst_subresources.aspect = dst_tex->read_aspect_flags;2316copy_region.dst_subresources.mipmap = p_dst_mipmap;2317copy_region.dst_subresources.base_layer = p_dst_layer;2318copy_region.dst_subresources.layer_count = 1;2319copy_region.dst_offset = p_to;23202321copy_region.size = p_size;23222323// Indicate the texture will get modified for the shared texture fallback.2324_texture_update_shared_fallback(p_to_texture, dst_tex, true);23252326// The textures must be mutable to be used in the copy operation.2327bool src_made_mutable = _texture_make_mutable(src_tex, p_from_texture);2328bool dst_made_mutable = _texture_make_mutable(dst_tex, p_to_texture);2329if (src_made_mutable || dst_made_mutable) {2330draw_graph.add_synchronization();2331}23322333draw_graph.add_texture_copy(src_tex->driver_id, src_tex->draw_tracker, dst_tex->driver_id, dst_tex->draw_tracker, copy_region);23342335return OK;2336}23372338Error RenderingDevice::texture_resolve_multisample(RID p_from_texture, RID p_to_texture) {2339ERR_RENDER_THREAD_GUARD_V(ERR_UNAVAILABLE);23402341Texture *src_tex = texture_owner.get_or_null(p_from_texture);2342ERR_FAIL_NULL_V(src_tex, ERR_INVALID_PARAMETER);23432344ERR_FAIL_COND_V_MSG(src_tex->bound, ERR_INVALID_PARAMETER,2345"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.");2346ERR_FAIL_COND_V_MSG(!(src_tex->usage_flags & TEXTURE_USAGE_CAN_COPY_FROM_BIT), ERR_INVALID_PARAMETER,2347"Source texture requires the `RenderingDevice.TEXTURE_USAGE_CAN_COPY_FROM_BIT` to be set to be retrieved.");23482349ERR_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)");2350ERR_FAIL_COND_V_MSG(src_tex->samples == TEXTURE_SAMPLES_1, ERR_INVALID_PARAMETER, "Source texture must be multisampled.");23512352Texture *dst_tex = texture_owner.get_or_null(p_to_texture);2353ERR_FAIL_NULL_V(dst_tex, ERR_INVALID_PARAMETER);23542355ERR_FAIL_COND_V_MSG(dst_tex->bound, ERR_INVALID_PARAMETER,2356"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.");2357ERR_FAIL_COND_V_MSG(!(dst_tex->usage_flags & TEXTURE_USAGE_CAN_COPY_TO_BIT), ERR_INVALID_PARAMETER,2358"Destination texture requires the `RenderingDevice.TEXTURE_USAGE_CAN_COPY_TO_BIT` to be set to be retrieved.");23592360ERR_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).");2361ERR_FAIL_COND_V_MSG(dst_tex->samples != TEXTURE_SAMPLES_1, ERR_INVALID_PARAMETER, "Destination texture must not be multisampled.");23622363ERR_FAIL_COND_V_MSG(src_tex->format != dst_tex->format, ERR_INVALID_PARAMETER, "Source and Destination textures must be the same format.");2364ERR_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.");23652366ERR_FAIL_COND_V_MSG(src_tex->read_aspect_flags != dst_tex->read_aspect_flags, ERR_INVALID_PARAMETER,2367"Source and destination texture must be of the same type (color or depth).");23682369// Indicate the texture will get modified for the shared texture fallback.2370_texture_update_shared_fallback(p_to_texture, dst_tex, true);23712372_check_transfer_worker_texture(src_tex);2373_check_transfer_worker_texture(dst_tex);23742375// The textures must be mutable to be used in the resolve operation.2376bool src_made_mutable = _texture_make_mutable(src_tex, p_from_texture);2377bool dst_made_mutable = _texture_make_mutable(dst_tex, p_to_texture);2378if (src_made_mutable || dst_made_mutable) {2379draw_graph.add_synchronization();2380}23812382draw_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);23832384return OK;2385}23862387void RenderingDevice::texture_set_discardable(RID p_texture, bool p_discardable) {2388ERR_RENDER_THREAD_GUARD();23892390Texture *texture = texture_owner.get_or_null(p_texture);2391ERR_FAIL_NULL(texture);23922393texture->is_discardable = p_discardable;23942395if (texture->draw_tracker != nullptr) {2396texture->draw_tracker->is_discardable = p_discardable;2397}23982399if (texture->shared_fallback != nullptr && texture->shared_fallback->texture_tracker != nullptr) {2400texture->shared_fallback->texture_tracker->is_discardable = p_discardable;2401}2402}24032404bool RenderingDevice::texture_is_discardable(RID p_texture) {2405ERR_RENDER_THREAD_GUARD_V(false);24062407Texture *texture = texture_owner.get_or_null(p_texture);2408ERR_FAIL_NULL_V(texture, false);24092410return texture->is_discardable;2411}24122413Error 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) {2414ERR_RENDER_THREAD_GUARD_V(ERR_UNAVAILABLE);24152416Texture *src_tex = texture_owner.get_or_null(p_texture);2417ERR_FAIL_NULL_V(src_tex, ERR_INVALID_PARAMETER);24182419ERR_FAIL_COND_V_MSG(src_tex->bound, ERR_INVALID_PARAMETER,2420"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.");24212422ERR_FAIL_COND_V(p_layers == 0, ERR_INVALID_PARAMETER);2423ERR_FAIL_COND_V(p_mipmaps == 0, ERR_INVALID_PARAMETER);24242425ERR_FAIL_COND_V_MSG(!(src_tex->usage_flags & TEXTURE_USAGE_CAN_COPY_TO_BIT), ERR_INVALID_PARAMETER,2426"Source texture requires the `RenderingDevice.TEXTURE_USAGE_CAN_COPY_TO_BIT` to be set to be cleared.");24272428ERR_FAIL_COND_V(p_base_mipmap + p_mipmaps > src_tex->mipmaps, ERR_INVALID_PARAMETER);2429ERR_FAIL_COND_V(p_base_layer + p_layers > src_tex->layers, ERR_INVALID_PARAMETER);24302431_check_transfer_worker_texture(src_tex);24322433RDD::TextureSubresourceRange range;2434range.aspect = src_tex->read_aspect_flags;2435range.base_mipmap = src_tex->base_mipmap + p_base_mipmap;2436range.mipmap_count = p_mipmaps;2437range.base_layer = src_tex->base_layer + p_base_layer;2438range.layer_count = p_layers;24392440// Indicate the texture will get modified for the shared texture fallback.2441_texture_update_shared_fallback(p_texture, src_tex, true);24422443if (_texture_make_mutable(src_tex, p_texture)) {2444// The texture must be mutable to be used as a clear destination.2445draw_graph.add_synchronization();2446}24472448draw_graph.add_texture_clear(src_tex->driver_id, src_tex->draw_tracker, p_color, range);24492450return OK;2451}24522453bool RenderingDevice::texture_is_format_supported_for_usage(DataFormat p_format, BitField<RenderingDevice::TextureUsageBits> p_usage) const {2454ERR_FAIL_INDEX_V(p_format, DATA_FORMAT_MAX, false);24552456bool cpu_readable = (p_usage & RDD::TEXTURE_USAGE_CPU_READ_BIT);2457BitField<TextureUsageBits> supported = driver->texture_get_usages_supported_by_format(p_format, cpu_readable);2458bool any_unsupported = (((int64_t)supported) | ((int64_t)p_usage)) != ((int64_t)supported);2459return !any_unsupported;2460}24612462/*********************/2463/**** FRAMEBUFFER ****/2464/*********************/24652466RDD::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) {2467// NOTE:2468// Before the refactor to RenderingDevice-RenderingDeviceDriver, there was commented out code to2469// specify dependencies to external subpasses. Since it had been unused for a long timel it wasn't ported2470// to the new architecture.24712472LocalVector<int32_t> attachment_last_pass;2473attachment_last_pass.resize(p_attachments.size());24742475if (p_view_count > 1) {2476const RDD::MultiviewCapabilities &capabilities = p_driver->get_multiview_capabilities();24772478// This only works with multiview!2479ERR_FAIL_COND_V_MSG(!capabilities.is_supported, RDD::RenderPassID(), "Multiview not supported");24802481// Make sure we limit this to the number of views we support.2482ERR_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");2483}24842485LocalVector<RDD::Attachment> attachments;2486LocalVector<uint32_t> attachment_remap;24872488for (int i = 0; i < p_attachments.size(); i++) {2489if (p_attachments[i].usage_flags == AttachmentFormat::UNUSED_ATTACHMENT) {2490attachment_remap.push_back(RDD::AttachmentReference::UNUSED);2491continue;2492}24932494ERR_FAIL_INDEX_V(p_attachments[i].format, DATA_FORMAT_MAX, RDD::RenderPassID());2495ERR_FAIL_INDEX_V(p_attachments[i].samples, TEXTURE_SAMPLES_MAX, RDD::RenderPassID());2496ERR_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)),2497RDD::RenderPassID(), "Texture format for index (" + itos(i) + ") requires an attachment (color, depth-stencil, input or VRS) bit set.");24982499RDD::Attachment description;2500description.format = p_attachments[i].format;2501description.samples = p_attachments[i].samples;25022503// We can setup a framebuffer where we write to our VRS texture to set it up.2504// We make the assumption here that if our texture is actually used as our VRS attachment.2505// It is used as such for each subpass. This is fairly certain seeing the restrictions on subpasses.2506bool is_vrs = (p_attachments[i].usage_flags & TEXTURE_USAGE_VRS_ATTACHMENT_BIT) && i == p_vrs_attachment;2507if (is_vrs) {2508description.load_op = RDD::ATTACHMENT_LOAD_OP_LOAD;2509description.store_op = RDD::ATTACHMENT_STORE_OP_DONT_CARE;2510description.stencil_load_op = RDD::ATTACHMENT_LOAD_OP_DONT_CARE;2511description.stencil_store_op = RDD::ATTACHMENT_STORE_OP_DONT_CARE;2512description.initial_layout = _vrs_layout_from_method(p_vrs_method);2513description.final_layout = _vrs_layout_from_method(p_vrs_method);2514} else {2515if (p_attachments[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) {2516description.load_op = p_load_ops[i];2517description.store_op = p_store_ops[i];2518description.stencil_load_op = RDD::ATTACHMENT_LOAD_OP_DONT_CARE;2519description.stencil_store_op = RDD::ATTACHMENT_STORE_OP_DONT_CARE;2520description.initial_layout = RDD::TEXTURE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;2521description.final_layout = RDD::TEXTURE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;2522} else if (p_attachments[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {2523description.load_op = p_load_ops[i];2524description.store_op = p_store_ops[i];2525description.stencil_load_op = p_load_ops[i];2526description.stencil_store_op = p_store_ops[i];2527description.initial_layout = RDD::TEXTURE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;2528description.final_layout = RDD::TEXTURE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;2529} else {2530description.load_op = RDD::ATTACHMENT_LOAD_OP_DONT_CARE;2531description.store_op = RDD::ATTACHMENT_STORE_OP_DONT_CARE;2532description.stencil_load_op = RDD::ATTACHMENT_LOAD_OP_DONT_CARE;2533description.stencil_store_op = RDD::ATTACHMENT_STORE_OP_DONT_CARE;2534description.initial_layout = RDD::TEXTURE_LAYOUT_UNDEFINED;2535description.final_layout = RDD::TEXTURE_LAYOUT_UNDEFINED;2536}2537}25382539attachment_last_pass[i] = -1;2540attachment_remap.push_back(attachments.size());2541attachments.push_back(description);2542}25432544LocalVector<RDD::Subpass> subpasses;2545subpasses.resize(p_passes.size());2546LocalVector<RDD::SubpassDependency> subpass_dependencies;25472548for (int i = 0; i < p_passes.size(); i++) {2549const FramebufferPass *pass = &p_passes[i];2550RDD::Subpass &subpass = subpasses[i];25512552TextureSamples texture_samples = TEXTURE_SAMPLES_1;2553bool is_multisample_first = true;25542555for (int j = 0; j < pass->color_attachments.size(); j++) {2556int32_t attachment = pass->color_attachments[j];2557RDD::AttachmentReference reference;2558if (attachment == ATTACHMENT_UNUSED) {2559reference.attachment = RDD::AttachmentReference::UNUSED;2560reference.layout = RDD::TEXTURE_LAYOUT_UNDEFINED;2561} else {2562ERR_FAIL_INDEX_V_MSG(attachment, p_attachments.size(), RDD::RenderPassID(), "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), color attachment (" + itos(j) + ").");2563ERR_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.");2564ERR_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.");25652566if (is_multisample_first) {2567texture_samples = p_attachments[attachment].samples;2568is_multisample_first = false;2569} else {2570ERR_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.");2571}2572reference.attachment = attachment_remap[attachment];2573reference.layout = RDD::TEXTURE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;2574attachment_last_pass[attachment] = i;2575}2576reference.aspect = RDD::TEXTURE_ASPECT_COLOR_BIT;2577subpass.color_references.push_back(reference);2578}25792580for (int j = 0; j < pass->input_attachments.size(); j++) {2581int32_t attachment = pass->input_attachments[j];2582RDD::AttachmentReference reference;2583if (attachment == ATTACHMENT_UNUSED) {2584reference.attachment = RDD::AttachmentReference::UNUSED;2585reference.layout = RDD::TEXTURE_LAYOUT_UNDEFINED;2586} else {2587ERR_FAIL_INDEX_V_MSG(attachment, p_attachments.size(), RDD::RenderPassID(), "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), input attachment (" + itos(j) + ").");2588ERR_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.");2589ERR_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.");2590reference.attachment = attachment_remap[attachment];2591reference.layout = RDD::TEXTURE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;2592attachment_last_pass[attachment] = i;2593}2594reference.aspect = RDD::TEXTURE_ASPECT_COLOR_BIT;2595subpass.input_references.push_back(reference);2596}25972598if (pass->resolve_attachments.size() > 0) {2599ERR_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()) + ").");2600ERR_FAIL_COND_V_MSG(texture_samples == TEXTURE_SAMPLES_1, RDD::RenderPassID(), "Resolve attachments specified, but color attachments are not multisample.");2601}2602for (int j = 0; j < pass->resolve_attachments.size(); j++) {2603int32_t attachment = pass->resolve_attachments[j];2604attachments[attachment].load_op = RDD::ATTACHMENT_LOAD_OP_DONT_CARE;26052606RDD::AttachmentReference reference;2607if (attachment == ATTACHMENT_UNUSED) {2608reference.attachment = RDD::AttachmentReference::UNUSED;2609reference.layout = RDD::TEXTURE_LAYOUT_UNDEFINED;2610} else {2611ERR_FAIL_INDEX_V_MSG(attachment, p_attachments.size(), RDD::RenderPassID(), "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), resolve attachment (" + itos(j) + ").");2612ERR_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.");2613ERR_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.");2614ERR_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.");2615bool multisample = p_attachments[attachment].samples > TEXTURE_SAMPLES_1;2616ERR_FAIL_COND_V_MSG(multisample, RDD::RenderPassID(), "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), resolve attachments can't be multisample.");2617reference.attachment = attachment_remap[attachment];2618reference.layout = RDD::TEXTURE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; // RDD::TEXTURE_LAYOUT_SHADER_READ_ONLY_OPTIMAL2619attachment_last_pass[attachment] = i;2620}2621reference.aspect = RDD::TEXTURE_ASPECT_COLOR_BIT;2622subpass.resolve_references.push_back(reference);2623}26242625if (pass->depth_attachment != ATTACHMENT_UNUSED) {2626int32_t attachment = pass->depth_attachment;2627ERR_FAIL_INDEX_V_MSG(attachment, p_attachments.size(), RDD::RenderPassID(), "Invalid framebuffer depth format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), depth attachment.");2628ERR_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.");2629ERR_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.");2630subpass.depth_stencil_reference.attachment = attachment_remap[attachment];2631subpass.depth_stencil_reference.layout = RDD::TEXTURE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;2632attachment_last_pass[attachment] = i;26332634if (is_multisample_first) {2635texture_samples = p_attachments[attachment].samples;2636is_multisample_first = false;2637} else {2638ERR_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.");2639}26402641} else {2642subpass.depth_stencil_reference.attachment = RDD::AttachmentReference::UNUSED;2643subpass.depth_stencil_reference.layout = RDD::TEXTURE_LAYOUT_UNDEFINED;2644}26452646if (p_vrs_method == VRS_METHOD_FRAGMENT_SHADING_RATE && p_vrs_attachment >= 0) {2647int32_t attachment = p_vrs_attachment;2648ERR_FAIL_INDEX_V_MSG(attachment, p_attachments.size(), RDD::RenderPassID(), "Invalid framebuffer VRS format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), VRS attachment.");2649ERR_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.");2650ERR_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.");26512652subpass.fragment_shading_rate_reference.attachment = attachment_remap[attachment];2653subpass.fragment_shading_rate_reference.layout = RDD::TEXTURE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL;2654subpass.fragment_shading_rate_texel_size = p_vrs_texel_size;26552656attachment_last_pass[attachment] = i;2657}26582659for (int j = 0; j < pass->preserve_attachments.size(); j++) {2660int32_t attachment = pass->preserve_attachments[j];26612662ERR_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.");26632664ERR_FAIL_INDEX_V_MSG(attachment, p_attachments.size(), RDD::RenderPassID(), "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), preserve attachment (" + itos(j) + ").");26652666if (attachment_last_pass[attachment] != i) {2667// Preserve can still be used to keep depth or color from being discarded after use.2668attachment_last_pass[attachment] = i;2669subpasses[i].preserve_attachments.push_back(attachment);2670}2671}26722673if (r_samples) {2674r_samples->push_back(texture_samples);2675}26762677if (i > 0) {2678RDD::SubpassDependency dependency;2679dependency.src_subpass = i - 1;2680dependency.dst_subpass = i;2681dependency.src_stages = (RDD::PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | RDD::PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | RDD::PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT);2682dependency.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);2683dependency.src_access = (RDD::BARRIER_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | RDD::BARRIER_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT);2684dependency.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);2685subpass_dependencies.push_back(dependency);2686}2687}26882689RDD::AttachmentReference fragment_density_map_attachment_reference;2690if (p_vrs_method == VRS_METHOD_FRAGMENT_DENSITY_MAP && p_vrs_attachment >= 0) {2691fragment_density_map_attachment_reference.attachment = p_vrs_attachment;2692fragment_density_map_attachment_reference.layout = RDD::TEXTURE_LAYOUT_FRAGMENT_DENSITY_MAP_ATTACHMENT_OPTIMAL;2693}26942695RDD::RenderPassID render_pass = p_driver->render_pass_create(attachments, subpasses, subpass_dependencies, p_view_count, fragment_density_map_attachment_reference);2696ERR_FAIL_COND_V(!render_pass, RDD::RenderPassID());26972698return render_pass;2699}27002701RDD::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) {2702DEV_ASSERT(p_driver != nullptr);2703DEV_ASSERT(p_user_data != nullptr);27042705// The graph delegates the creation of the render pass to the user according to the load and store ops that were determined as necessary after2706// resolving the dependencies between commands. This function creates a render pass for the framebuffer accordingly.2707Framebuffer *framebuffer = (Framebuffer *)(p_user_data);2708const FramebufferFormatKey &key = framebuffer->rendering_device->framebuffer_formats[framebuffer->format_id].E->key();2709return _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);2710}27112712RDG::ResourceUsage RenderingDevice::_vrs_usage_from_method(VRSMethod p_method) {2713switch (p_method) {2714case VRS_METHOD_FRAGMENT_SHADING_RATE:2715return RDG::RESOURCE_USAGE_ATTACHMENT_FRAGMENT_SHADING_RATE_READ;2716case VRS_METHOD_FRAGMENT_DENSITY_MAP:2717return RDG::RESOURCE_USAGE_ATTACHMENT_FRAGMENT_DENSITY_MAP_READ;2718default:2719return RDG::RESOURCE_USAGE_NONE;2720}2721}27222723RDD::PipelineStageBits RenderingDevice::_vrs_stages_from_method(VRSMethod p_method) {2724switch (p_method) {2725case VRS_METHOD_FRAGMENT_SHADING_RATE:2726return RDD::PIPELINE_STAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT;2727case VRS_METHOD_FRAGMENT_DENSITY_MAP:2728return RDD::PIPELINE_STAGE_FRAGMENT_DENSITY_PROCESS_BIT;2729default:2730return RDD::PipelineStageBits(0);2731}2732}27332734RDD::TextureLayout RenderingDevice::_vrs_layout_from_method(VRSMethod p_method) {2735switch (p_method) {2736case VRS_METHOD_FRAGMENT_SHADING_RATE:2737return RDD::TEXTURE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL;2738case VRS_METHOD_FRAGMENT_DENSITY_MAP:2739return RDD::TEXTURE_LAYOUT_FRAGMENT_DENSITY_MAP_ATTACHMENT_OPTIMAL;2740default:2741return RDD::TEXTURE_LAYOUT_UNDEFINED;2742}2743}27442745void RenderingDevice::_vrs_detect_method() {2746const RDD::FragmentShadingRateCapabilities &fsr_capabilities = driver->get_fragment_shading_rate_capabilities();2747const RDD::FragmentDensityMapCapabilities &fdm_capabilities = driver->get_fragment_density_map_capabilities();2748if (fsr_capabilities.attachment_supported) {2749vrs_method = VRS_METHOD_FRAGMENT_SHADING_RATE;2750} else if (fdm_capabilities.attachment_supported) {2751vrs_method = VRS_METHOD_FRAGMENT_DENSITY_MAP;2752}27532754switch (vrs_method) {2755case VRS_METHOD_FRAGMENT_SHADING_RATE:2756vrs_format = DATA_FORMAT_R8_UINT;2757vrs_texel_size = Vector2i(16, 16).clamp(fsr_capabilities.min_texel_size, fsr_capabilities.max_texel_size);2758break;2759case VRS_METHOD_FRAGMENT_DENSITY_MAP:2760vrs_format = DATA_FORMAT_R8G8_UNORM;2761vrs_texel_size = Vector2i(32, 32).clamp(fdm_capabilities.min_texel_size, fdm_capabilities.max_texel_size);2762break;2763default:2764break;2765}2766}27672768RD::VRSMethod RenderingDevice::vrs_get_method() const {2769return vrs_method;2770}27712772RD::DataFormat RenderingDevice::vrs_get_format() const {2773return vrs_format;2774}27752776Size2i RenderingDevice::vrs_get_texel_size() const {2777return vrs_texel_size;2778}27792780RenderingDevice::FramebufferFormatID RenderingDevice::framebuffer_format_create(const Vector<AttachmentFormat> &p_format, uint32_t p_view_count, int32_t p_fragment_density_map_attachment) {2781FramebufferPass pass;2782for (int i = 0; i < p_format.size(); i++) {2783if (p_format[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {2784pass.depth_attachment = i;2785} else {2786pass.color_attachments.push_back(i);2787}2788}27892790Vector<FramebufferPass> passes;2791passes.push_back(pass);2792return framebuffer_format_create_multipass(p_format, passes, p_view_count, p_fragment_density_map_attachment);2793}27942795RenderingDevice::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) {2796_THREAD_SAFE_METHOD_27972798FramebufferFormatKey key;2799key.attachments = p_attachments;2800key.passes = p_passes;2801key.view_count = p_view_count;2802key.vrs_method = vrs_method;2803key.vrs_attachment = p_vrs_attachment;2804key.vrs_texel_size = vrs_texel_size;28052806const RBMap<FramebufferFormatKey, FramebufferFormatID>::Element *E = framebuffer_format_cache.find(key);2807if (E) {2808// Exists, return.2809return E->get();2810}28112812Vector<TextureSamples> samples;2813LocalVector<RDD::AttachmentLoadOp> load_ops;2814LocalVector<RDD::AttachmentStoreOp> store_ops;2815for (int64_t i = 0; i < p_attachments.size(); i++) {2816load_ops.push_back(RDD::ATTACHMENT_LOAD_OP_CLEAR);2817store_ops.push_back(RDD::ATTACHMENT_STORE_OP_STORE);2818}28192820RDD::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.2821if (!render_pass) { // Was likely invalid.2822return INVALID_ID;2823}28242825FramebufferFormatID id = FramebufferFormatID(framebuffer_format_cache.size()) | (FramebufferFormatID(ID_TYPE_FRAMEBUFFER_FORMAT) << FramebufferFormatID(ID_BASE_SHIFT));2826E = framebuffer_format_cache.insert(key, id);28272828FramebufferFormat fb_format;2829fb_format.E = E;2830fb_format.render_pass = render_pass;2831fb_format.pass_samples = samples;2832fb_format.view_count = p_view_count;2833framebuffer_formats[id] = fb_format;28342835#if PRINT_FRAMEBUFFER_FORMAT2836print_line("FRAMEBUFFER FORMAT:", id, "ATTACHMENTS:", p_attachments.size(), "PASSES:", p_passes.size());2837for (RD::AttachmentFormat attachment : p_attachments) {2838print_line("FORMAT:", attachment.format, "SAMPLES:", attachment.samples, "USAGE FLAGS:", attachment.usage_flags);2839}2840#endif28412842return id;2843}28442845RenderingDevice::FramebufferFormatID RenderingDevice::framebuffer_format_create_empty(TextureSamples p_samples) {2846_THREAD_SAFE_METHOD_28472848FramebufferFormatKey key;2849key.passes.push_back(FramebufferPass());28502851const RBMap<FramebufferFormatKey, FramebufferFormatID>::Element *E = framebuffer_format_cache.find(key);2852if (E) {2853// Exists, return.2854return E->get();2855}28562857LocalVector<RDD::Subpass> subpass;2858subpass.resize(1);28592860RDD::RenderPassID render_pass = driver->render_pass_create({}, subpass, {}, 1, RDD::AttachmentReference());2861ERR_FAIL_COND_V(!render_pass, FramebufferFormatID());28622863FramebufferFormatID id = FramebufferFormatID(framebuffer_format_cache.size()) | (FramebufferFormatID(ID_TYPE_FRAMEBUFFER_FORMAT) << FramebufferFormatID(ID_BASE_SHIFT));28642865E = framebuffer_format_cache.insert(key, id);28662867FramebufferFormat fb_format;2868fb_format.E = E;2869fb_format.render_pass = render_pass;2870fb_format.pass_samples.push_back(p_samples);2871framebuffer_formats[id] = fb_format;28722873#if PRINT_FRAMEBUFFER_FORMAT2874print_line("FRAMEBUFFER FORMAT:", id, "ATTACHMENTS: EMPTY");2875#endif28762877return id;2878}28792880RenderingDevice::TextureSamples RenderingDevice::framebuffer_format_get_texture_samples(FramebufferFormatID p_format, uint32_t p_pass) {2881_THREAD_SAFE_METHOD_28822883HashMap<FramebufferFormatID, FramebufferFormat>::Iterator E = framebuffer_formats.find(p_format);2884ERR_FAIL_COND_V(!E, TEXTURE_SAMPLES_1);2885ERR_FAIL_COND_V(p_pass >= uint32_t(E->value.pass_samples.size()), TEXTURE_SAMPLES_1);28862887return E->value.pass_samples[p_pass];2888}28892890RID RenderingDevice::framebuffer_create_empty(const Size2i &p_size, TextureSamples p_samples, FramebufferFormatID p_format_check) {2891_THREAD_SAFE_METHOD_28922893Framebuffer framebuffer;2894framebuffer.rendering_device = this;2895framebuffer.format_id = framebuffer_format_create_empty(p_samples);2896ERR_FAIL_COND_V(p_format_check != INVALID_FORMAT_ID && framebuffer.format_id != p_format_check, RID());2897framebuffer.size = p_size;2898framebuffer.view_count = 1;28992900RDG::FramebufferCache *framebuffer_cache = RDG::framebuffer_cache_create();2901framebuffer_cache->width = p_size.width;2902framebuffer_cache->height = p_size.height;2903framebuffer.framebuffer_cache = framebuffer_cache;29042905RID id = framebuffer_owner.make_rid(framebuffer);2906#ifdef DEV_ENABLED2907set_resource_name(id, "RID:" + itos(id.get_id()));2908#endif29092910framebuffer_cache->render_pass_creation_user_data = framebuffer_owner.get_or_null(id);29112912return id;2913}29142915RID RenderingDevice::framebuffer_create(const Vector<RID> &p_texture_attachments, FramebufferFormatID p_format_check, uint32_t p_view_count) {2916_THREAD_SAFE_METHOD_29172918FramebufferPass pass;29192920for (int i = 0; i < p_texture_attachments.size(); i++) {2921Texture *texture = texture_owner.get_or_null(p_texture_attachments[i]);29222923ERR_FAIL_COND_V_MSG(texture && texture->layers != p_view_count, RID(), "Layers of our texture doesn't match view count for this framebuffer");29242925if (texture != nullptr) {2926_check_transfer_worker_texture(texture);2927}29282929if (texture && texture->usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {2930pass.depth_attachment = i;2931} else if (texture && texture->usage_flags & TEXTURE_USAGE_VRS_ATTACHMENT_BIT) {2932// Prevent the VRS attachment from being added to the color_attachments.2933} else {2934if (texture && texture->is_resolve_buffer) {2935pass.resolve_attachments.push_back(i);2936} else {2937pass.color_attachments.push_back(texture ? i : ATTACHMENT_UNUSED);2938}2939}2940}29412942Vector<FramebufferPass> passes;2943passes.push_back(pass);29442945return framebuffer_create_multipass(p_texture_attachments, passes, p_format_check, p_view_count);2946}29472948RID RenderingDevice::framebuffer_create_multipass(const Vector<RID> &p_texture_attachments, const Vector<FramebufferPass> &p_passes, FramebufferFormatID p_format_check, uint32_t p_view_count) {2949_THREAD_SAFE_METHOD_29502951Vector<AttachmentFormat> attachments;2952LocalVector<RDD::TextureID> textures;2953LocalVector<RDG::ResourceTracker *> trackers;2954int32_t vrs_attachment = -1;2955attachments.resize(p_texture_attachments.size());2956Size2i size;2957bool size_set = false;2958for (int i = 0; i < p_texture_attachments.size(); i++) {2959AttachmentFormat af;2960Texture *texture = texture_owner.get_or_null(p_texture_attachments[i]);2961if (!texture) {2962af.usage_flags = AttachmentFormat::UNUSED_ATTACHMENT;2963trackers.push_back(nullptr);2964} else {2965ERR_FAIL_COND_V_MSG(texture->layers != p_view_count, RID(), "Layers of our texture doesn't match view count for this framebuffer");29662967_check_transfer_worker_texture(texture);29682969if (i != 0 && texture->usage_flags & TEXTURE_USAGE_VRS_ATTACHMENT_BIT) {2970// Detect if the texture is the fragment density map and it's not the first attachment.2971vrs_attachment = i;2972}29732974if (!size_set) {2975size.width = texture->width;2976size.height = texture->height;2977size_set = true;2978} else if (texture->usage_flags & TEXTURE_USAGE_VRS_ATTACHMENT_BIT) {2979// If this is not the first attachment we assume this is used as the VRS attachment.2980// In this case this texture will be 1/16th the size of the color attachment.2981// So we skip the size check.2982} else {2983ERR_FAIL_COND_V_MSG((uint32_t)size.width != texture->width || (uint32_t)size.height != texture->height, RID(),2984"All textures in a framebuffer should be the same size.");2985}29862987af.format = texture->format;2988af.samples = texture->samples;2989af.usage_flags = texture->usage_flags;29902991_texture_make_mutable(texture, p_texture_attachments[i]);29922993textures.push_back(texture->driver_id);2994trackers.push_back(texture->draw_tracker);2995}2996attachments.write[i] = af;2997}29982999ERR_FAIL_COND_V_MSG(!size_set, RID(), "All attachments unused.");30003001FramebufferFormatID format_id = framebuffer_format_create_multipass(attachments, p_passes, p_view_count, vrs_attachment);3002if (format_id == INVALID_ID) {3003return RID();3004}30053006ERR_FAIL_COND_V_MSG(p_format_check != INVALID_ID && format_id != p_format_check, RID(),3007"The format used to check this framebuffer differs from the intended framebuffer format.");30083009Framebuffer framebuffer;3010framebuffer.rendering_device = this;3011framebuffer.format_id = format_id;3012framebuffer.texture_ids = p_texture_attachments;3013framebuffer.size = size;3014framebuffer.view_count = p_view_count;30153016RDG::FramebufferCache *framebuffer_cache = RDG::framebuffer_cache_create();3017framebuffer_cache->width = size.width;3018framebuffer_cache->height = size.height;3019framebuffer_cache->textures = textures;3020framebuffer_cache->trackers = trackers;3021framebuffer.framebuffer_cache = framebuffer_cache;30223023RID id = framebuffer_owner.make_rid(framebuffer);3024#ifdef DEV_ENABLED3025set_resource_name(id, "RID:" + itos(id.get_id()));3026#endif30273028for (int i = 0; i < p_texture_attachments.size(); i++) {3029if (p_texture_attachments[i].is_valid()) {3030_add_dependency(id, p_texture_attachments[i]);3031}3032}30333034framebuffer_cache->render_pass_creation_user_data = framebuffer_owner.get_or_null(id);30353036return id;3037}30383039RenderingDevice::FramebufferFormatID RenderingDevice::framebuffer_get_format(RID p_framebuffer) {3040_THREAD_SAFE_METHOD_30413042Framebuffer *framebuffer = framebuffer_owner.get_or_null(p_framebuffer);3043ERR_FAIL_NULL_V(framebuffer, INVALID_ID);30443045return framebuffer->format_id;3046}30473048Size2 RenderingDevice::framebuffer_get_size(RID p_framebuffer) {3049_THREAD_SAFE_METHOD_30503051Framebuffer *framebuffer = framebuffer_owner.get_or_null(p_framebuffer);3052ERR_FAIL_NULL_V(framebuffer, Size2(0, 0));30533054return framebuffer->size;3055}30563057bool RenderingDevice::framebuffer_is_valid(RID p_framebuffer) const {3058_THREAD_SAFE_METHOD_30593060return framebuffer_owner.owns(p_framebuffer);3061}30623063void RenderingDevice::framebuffer_set_invalidation_callback(RID p_framebuffer, InvalidationCallback p_callback, void *p_userdata) {3064_THREAD_SAFE_METHOD_30653066Framebuffer *framebuffer = framebuffer_owner.get_or_null(p_framebuffer);3067ERR_FAIL_NULL(framebuffer);30683069framebuffer->invalidated_callback = p_callback;3070framebuffer->invalidated_callback_userdata = p_userdata;3071}30723073/*****************/3074/**** SAMPLER ****/3075/*****************/30763077RID RenderingDevice::sampler_create(const SamplerState &p_state) {3078_THREAD_SAFE_METHOD_30793080ERR_FAIL_INDEX_V(p_state.repeat_u, SAMPLER_REPEAT_MODE_MAX, RID());3081ERR_FAIL_INDEX_V(p_state.repeat_v, SAMPLER_REPEAT_MODE_MAX, RID());3082ERR_FAIL_INDEX_V(p_state.repeat_w, SAMPLER_REPEAT_MODE_MAX, RID());3083ERR_FAIL_INDEX_V(p_state.compare_op, COMPARE_OP_MAX, RID());3084ERR_FAIL_INDEX_V(p_state.border_color, SAMPLER_BORDER_COLOR_MAX, RID());30853086RDD::SamplerID sampler = driver->sampler_create(p_state);3087ERR_FAIL_COND_V(!sampler, RID());30883089RID id = sampler_owner.make_rid(sampler);3090#ifdef DEV_ENABLED3091set_resource_name(id, "RID:" + itos(id.get_id()));3092#endif3093return id;3094}30953096bool RenderingDevice::sampler_is_format_supported_for_filter(DataFormat p_format, SamplerFilter p_sampler_filter) const {3097_THREAD_SAFE_METHOD_30983099ERR_FAIL_INDEX_V(p_format, DATA_FORMAT_MAX, false);31003101return driver->sampler_is_format_supported_for_filter(p_format, p_sampler_filter);3102}31033104/***********************/3105/**** VERTEX BUFFER ****/3106/***********************/31073108RID RenderingDevice::vertex_buffer_create(uint32_t p_size_bytes, Span<uint8_t> p_data, BitField<BufferCreationBits> p_creation_bits) {3109ERR_FAIL_COND_V(p_data.size() && (uint32_t)p_data.size() != p_size_bytes, RID());31103111Buffer buffer;3112buffer.size = p_size_bytes;3113buffer.usage = RDD::BUFFER_USAGE_TRANSFER_FROM_BIT | RDD::BUFFER_USAGE_TRANSFER_TO_BIT | RDD::BUFFER_USAGE_VERTEX_BIT;3114if (p_creation_bits.has_flag(BUFFER_CREATION_AS_STORAGE_BIT)) {3115buffer.usage.set_flag(RDD::BUFFER_USAGE_STORAGE_BIT);3116}3117if (p_creation_bits.has_flag(BUFFER_CREATION_DEVICE_ADDRESS_BIT)) {3118buffer.usage.set_flag(RDD::BUFFER_USAGE_DEVICE_ADDRESS_BIT);3119}3120buffer.driver_id = driver->buffer_create(buffer.size, buffer.usage, RDD::MEMORY_ALLOCATION_TYPE_GPU);3121ERR_FAIL_COND_V(!buffer.driver_id, RID());31223123// Vertex buffers are assumed to be immutable unless they don't have initial data or they've been marked for storage explicitly.3124if (p_data.is_empty() || p_creation_bits.has_flag(BUFFER_CREATION_AS_STORAGE_BIT)) {3125buffer.draw_tracker = RDG::resource_tracker_create();3126buffer.draw_tracker->buffer_driver_id = buffer.driver_id;3127}31283129if (p_data.size()) {3130_buffer_initialize(&buffer, p_data);3131}31323133_THREAD_SAFE_LOCK_3134buffer_memory += buffer.size;3135_THREAD_SAFE_UNLOCK_31363137RID id = vertex_buffer_owner.make_rid(buffer);3138#ifdef DEV_ENABLED3139set_resource_name(id, "RID:" + itos(id.get_id()));3140#endif3141return id;3142}31433144// 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.3145RenderingDevice::VertexFormatID RenderingDevice::vertex_format_create(const Vector<VertexAttribute> &p_vertex_descriptions) {3146_THREAD_SAFE_METHOD_31473148VertexDescriptionKey key;3149key.vertex_formats = p_vertex_descriptions;31503151VertexFormatID *idptr = vertex_format_cache.getptr(key);3152if (idptr) {3153return *idptr;3154}31553156HashSet<int> used_locations;3157for (int i = 0; i < p_vertex_descriptions.size(); i++) {3158ERR_CONTINUE(p_vertex_descriptions[i].format >= DATA_FORMAT_MAX);3159ERR_FAIL_COND_V(used_locations.has(p_vertex_descriptions[i].location), INVALID_ID);31603161ERR_FAIL_COND_V_MSG(get_format_vertex_size(p_vertex_descriptions[i].format) == 0, INVALID_ID,3162"Data format for attachment (" + itos(i) + "), '" + FORMAT_NAMES[p_vertex_descriptions[i].format] + "', is not valid for a vertex array.");31633164used_locations.insert(p_vertex_descriptions[i].location);3165}31663167RDD::VertexFormatID driver_id = driver->vertex_format_create(p_vertex_descriptions);3168ERR_FAIL_COND_V(!driver_id, 0);31693170VertexFormatID id = (vertex_format_cache.size() | ((int64_t)ID_TYPE_VERTEX_FORMAT << ID_BASE_SHIFT));3171vertex_format_cache[key] = id;3172vertex_formats[id].vertex_formats = p_vertex_descriptions;3173vertex_formats[id].driver_id = driver_id;3174return id;3175}31763177RID 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) {3178_THREAD_SAFE_METHOD_31793180ERR_FAIL_COND_V(!vertex_formats.has(p_vertex_format), RID());3181const VertexDescriptionCache &vd = vertex_formats[p_vertex_format];31823183ERR_FAIL_COND_V(vd.vertex_formats.size() != p_src_buffers.size(), RID());31843185for (int i = 0; i < p_src_buffers.size(); i++) {3186ERR_FAIL_COND_V(!vertex_buffer_owner.owns(p_src_buffers[i]), RID());3187}31883189VertexArray vertex_array;31903191if (p_offsets.is_empty()) {3192vertex_array.offsets.resize_initialized(p_src_buffers.size());3193} else {3194ERR_FAIL_COND_V(p_offsets.size() != p_src_buffers.size(), RID());3195vertex_array.offsets = p_offsets;3196}31973198vertex_array.vertex_count = p_vertex_count;3199vertex_array.description = p_vertex_format;3200vertex_array.max_instances_allowed = 0xFFFFFFFF; // By default as many as you want.3201for (int i = 0; i < p_src_buffers.size(); i++) {3202Buffer *buffer = vertex_buffer_owner.get_or_null(p_src_buffers[i]);32033204// Validate with buffer.3205{3206const VertexAttribute &atf = vd.vertex_formats[i];32073208uint32_t element_size = get_format_vertex_size(atf.format);3209ERR_FAIL_COND_V(element_size == 0, RID()); // Should never happens since this was prevalidated.32103211if (atf.frequency == VERTEX_FREQUENCY_VERTEX) {3212// Validate size for regular drawing.3213uint64_t total_size = uint64_t(atf.stride) * (p_vertex_count - 1) + atf.offset + element_size;3214ERR_FAIL_COND_V_MSG(total_size > buffer->size, RID(),3215"Attachment (" + itos(i) + ") will read past the end of the buffer.");32163217} else {3218// Validate size for instances drawing.3219uint64_t available = buffer->size - atf.offset;3220ERR_FAIL_COND_V_MSG(available < element_size, RID(),3221"Attachment (" + itos(i) + ") uses instancing, but it's just too small.");32223223uint32_t instances_allowed = available / atf.stride;3224vertex_array.max_instances_allowed = MIN(instances_allowed, vertex_array.max_instances_allowed);3225}3226}32273228vertex_array.buffers.push_back(buffer->driver_id);32293230if (buffer->draw_tracker != nullptr) {3231vertex_array.draw_trackers.push_back(buffer->draw_tracker);3232} else {3233vertex_array.untracked_buffers.insert(p_src_buffers[i]);3234}32353236if (buffer->transfer_worker_index >= 0) {3237vertex_array.transfer_worker_indices.push_back(buffer->transfer_worker_index);3238vertex_array.transfer_worker_operations.push_back(buffer->transfer_worker_operation);3239}3240}32413242RID id = vertex_array_owner.make_rid(vertex_array);3243for (int i = 0; i < p_src_buffers.size(); i++) {3244_add_dependency(id, p_src_buffers[i]);3245}32463247return id;3248}32493250RID 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) {3251ERR_FAIL_COND_V(p_index_count == 0, RID());32523253IndexBuffer index_buffer;3254index_buffer.format = p_format;3255index_buffer.supports_restart_indices = p_use_restart_indices;3256index_buffer.index_count = p_index_count;3257uint32_t size_bytes = p_index_count * ((p_format == INDEX_BUFFER_FORMAT_UINT16) ? 2 : 4);3258#ifdef DEBUG_ENABLED3259if (p_data.size()) {3260index_buffer.max_index = 0;3261ERR_FAIL_COND_V_MSG((uint32_t)p_data.size() != size_bytes, RID(),3262"Default index buffer initializer array size (" + itos(p_data.size()) + ") does not match format required size (" + itos(size_bytes) + ").");3263const uint8_t *r = p_data.ptr();3264if (p_format == INDEX_BUFFER_FORMAT_UINT16) {3265const uint16_t *index16 = (const uint16_t *)r;3266for (uint32_t i = 0; i < p_index_count; i++) {3267if (p_use_restart_indices && index16[i] == 0xFFFF) {3268continue; // Restart index, ignore.3269}3270index_buffer.max_index = MAX(index16[i], index_buffer.max_index);3271}3272} else {3273const uint32_t *index32 = (const uint32_t *)r;3274for (uint32_t i = 0; i < p_index_count; i++) {3275if (p_use_restart_indices && index32[i] == 0xFFFFFFFF) {3276continue; // Restart index, ignore.3277}3278index_buffer.max_index = MAX(index32[i], index_buffer.max_index);3279}3280}3281} else {3282index_buffer.max_index = 0xFFFFFFFF;3283}3284#else3285index_buffer.max_index = 0xFFFFFFFF;3286#endif3287index_buffer.size = size_bytes;3288index_buffer.usage = (RDD::BUFFER_USAGE_TRANSFER_FROM_BIT | RDD::BUFFER_USAGE_TRANSFER_TO_BIT | RDD::BUFFER_USAGE_INDEX_BIT);3289if (p_creation_bits.has_flag(BUFFER_CREATION_DEVICE_ADDRESS_BIT)) {3290index_buffer.usage.set_flag(RDD::BUFFER_USAGE_DEVICE_ADDRESS_BIT);3291}3292index_buffer.driver_id = driver->buffer_create(index_buffer.size, index_buffer.usage, RDD::MEMORY_ALLOCATION_TYPE_GPU);3293ERR_FAIL_COND_V(!index_buffer.driver_id, RID());32943295// Index buffers are assumed to be immutable unless they don't have initial data.3296if (p_data.is_empty()) {3297index_buffer.draw_tracker = RDG::resource_tracker_create();3298index_buffer.draw_tracker->buffer_driver_id = index_buffer.driver_id;3299}33003301if (p_data.size()) {3302_buffer_initialize(&index_buffer, p_data);3303}33043305_THREAD_SAFE_LOCK_3306buffer_memory += index_buffer.size;3307_THREAD_SAFE_UNLOCK_33083309RID id = index_buffer_owner.make_rid(index_buffer);3310#ifdef DEV_ENABLED3311set_resource_name(id, "RID:" + itos(id.get_id()));3312#endif3313return id;3314}33153316RID RenderingDevice::index_array_create(RID p_index_buffer, uint32_t p_index_offset, uint32_t p_index_count) {3317_THREAD_SAFE_METHOD_33183319ERR_FAIL_COND_V(!index_buffer_owner.owns(p_index_buffer), RID());33203321IndexBuffer *index_buffer = index_buffer_owner.get_or_null(p_index_buffer);33223323ERR_FAIL_COND_V(p_index_count == 0, RID());3324ERR_FAIL_COND_V(p_index_offset + p_index_count > index_buffer->index_count, RID());33253326IndexArray index_array;3327index_array.max_index = index_buffer->max_index;3328index_array.driver_id = index_buffer->driver_id;3329index_array.draw_tracker = index_buffer->draw_tracker;3330index_array.offset = p_index_offset;3331index_array.indices = p_index_count;3332index_array.format = index_buffer->format;3333index_array.supports_restart_indices = index_buffer->supports_restart_indices;3334index_array.transfer_worker_index = index_buffer->transfer_worker_index;3335index_array.transfer_worker_operation = index_buffer->transfer_worker_operation;33363337RID id = index_array_owner.make_rid(index_array);3338_add_dependency(id, p_index_buffer);3339return id;3340}33413342/****************/3343/**** SHADER ****/3344/****************/33453346static const char *SHADER_UNIFORM_NAMES[RenderingDevice::UNIFORM_TYPE_MAX] = {3347"Sampler", "CombinedSampler", "Texture", "Image", "TextureBuffer", "SamplerTextureBuffer", "ImageBuffer", "UniformBuffer", "StorageBuffer", "InputAttachment"3348};33493350String RenderingDevice::_shader_uniform_debug(RID p_shader, int p_set) {3351String ret;3352const Shader *shader = shader_owner.get_or_null(p_shader);3353ERR_FAIL_NULL_V(shader, String());3354for (int i = 0; i < shader->uniform_sets.size(); i++) {3355if (p_set >= 0 && i != p_set) {3356continue;3357}3358for (int j = 0; j < shader->uniform_sets[i].size(); j++) {3359const ShaderUniform &ui = shader->uniform_sets[i][j];3360if (!ret.is_empty()) {3361ret += "\n";3362}3363ret += "Set: " + itos(i) + " Binding: " + itos(ui.binding) + " Type: " + SHADER_UNIFORM_NAMES[ui.type] + " Writable: " + (ui.writable ? "Y" : "N") + " Length: " + itos(ui.length);3364}3365}3366return ret;3367}33683369Vector<uint8_t> RenderingDevice::shader_compile_binary_from_spirv(const Vector<ShaderStageSPIRVData> &p_spirv, const String &p_shader_name) {3370const RenderingShaderContainerFormat &container_format = driver->get_shader_container_format();3371Ref<RenderingShaderContainer> shader_container = container_format.create_container();3372ERR_FAIL_COND_V(shader_container.is_null(), Vector<uint8_t>());33733374// Compile shader binary from SPIR-V.3375bool code_compiled = shader_container->set_code_from_spirv(p_shader_name, p_spirv);3376ERR_FAIL_COND_V_MSG(!code_compiled, Vector<uint8_t>(), vformat("Failed to compile code to native for SPIR-V."));33773378return shader_container->to_bytes();3379}33803381RID RenderingDevice::shader_create_from_bytecode(const Vector<uint8_t> &p_shader_binary, RID p_placeholder) {3382// Immutable samplers :3383// Expanding api when creating shader to allow passing optionally a set of immutable samplers3384// keeping existing api but extending it by sending an empty set.3385Vector<PipelineImmutableSampler> immutable_samplers;3386return shader_create_from_bytecode_with_samplers(p_shader_binary, p_placeholder, immutable_samplers);3387}33883389RID RenderingDevice::shader_create_from_bytecode_with_samplers(const Vector<uint8_t> &p_shader_binary, RID p_placeholder, const Vector<PipelineImmutableSampler> &p_immutable_samplers) {3390_THREAD_SAFE_METHOD_33913392Ref<RenderingShaderContainer> shader_container = driver->get_shader_container_format().create_container();3393ERR_FAIL_COND_V(shader_container.is_null(), RID());33943395bool parsed_container = shader_container->from_bytes(p_shader_binary);3396ERR_FAIL_COND_V_MSG(!parsed_container, RID(), "Failed to parse shader container from binary.");33973398Vector<RDD::ImmutableSampler> driver_immutable_samplers;3399for (const PipelineImmutableSampler &source_sampler : p_immutable_samplers) {3400RDD::ImmutableSampler driver_sampler;3401driver_sampler.type = source_sampler.uniform_type;3402driver_sampler.binding = source_sampler.binding;34033404for (uint32_t j = 0; j < source_sampler.get_id_count(); j++) {3405RDD::SamplerID *sampler_driver_id = sampler_owner.get_or_null(source_sampler.get_id(j));3406driver_sampler.ids.push_back(*sampler_driver_id);3407}34083409driver_immutable_samplers.append(driver_sampler);3410}34113412RDD::ShaderID shader_id = driver->shader_create_from_container(shader_container, driver_immutable_samplers);3413ERR_FAIL_COND_V(!shader_id, RID());34143415// All good, let's create modules.34163417RID id;3418if (p_placeholder.is_null()) {3419id = shader_owner.make_rid();3420} else {3421id = p_placeholder;3422}34233424Shader *shader = shader_owner.get_or_null(id);3425ERR_FAIL_NULL_V(shader, RID());34263427*((ShaderReflection *)shader) = shader_container->get_shader_reflection();3428shader->name.clear();3429shader->name.append_utf8(shader_container->shader_name);3430shader->driver_id = shader_id;3431shader->layout_hash = driver->shader_get_layout_hash(shader_id);34323433for (int i = 0; i < shader->uniform_sets.size(); i++) {3434uint32_t format = 0; // No format, default.34353436if (shader->uniform_sets[i].size()) {3437// Sort and hash.34383439shader->uniform_sets.write[i].sort();34403441UniformSetFormat usformat;3442usformat.uniforms = shader->uniform_sets[i];3443RBMap<UniformSetFormat, uint32_t>::Element *E = uniform_set_format_cache.find(usformat);3444if (E) {3445format = E->get();3446} else {3447format = uniform_set_format_cache.size() + 1;3448uniform_set_format_cache.insert(usformat, format);3449}3450}34513452shader->set_formats.push_back(format);3453}34543455for (ShaderStage stage : shader->stages_vector) {3456switch (stage) {3457case SHADER_STAGE_VERTEX:3458shader->stage_bits.set_flag(RDD::PIPELINE_STAGE_VERTEX_SHADER_BIT);3459break;3460case SHADER_STAGE_FRAGMENT:3461shader->stage_bits.set_flag(RDD::PIPELINE_STAGE_FRAGMENT_SHADER_BIT);3462break;3463case SHADER_STAGE_TESSELATION_CONTROL:3464shader->stage_bits.set_flag(RDD::PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT);3465break;3466case SHADER_STAGE_TESSELATION_EVALUATION:3467shader->stage_bits.set_flag(RDD::PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT);3468break;3469case SHADER_STAGE_COMPUTE:3470shader->stage_bits.set_flag(RDD::PIPELINE_STAGE_COMPUTE_SHADER_BIT);3471break;3472default:3473DEV_ASSERT(false && "Unknown shader stage.");3474break;3475}3476}34773478#ifdef DEV_ENABLED3479set_resource_name(id, "RID:" + itos(id.get_id()));3480#endif3481return id;3482}34833484void RenderingDevice::shader_destroy_modules(RID p_shader) {3485Shader *shader = shader_owner.get_or_null(p_shader);3486ERR_FAIL_NULL(shader);3487driver->shader_destroy_modules(shader->driver_id);3488}34893490RID RenderingDevice::shader_create_placeholder() {3491_THREAD_SAFE_METHOD_34923493Shader shader;3494return shader_owner.make_rid(shader);3495}34963497uint64_t RenderingDevice::shader_get_vertex_input_attribute_mask(RID p_shader) {3498_THREAD_SAFE_METHOD_34993500const Shader *shader = shader_owner.get_or_null(p_shader);3501ERR_FAIL_NULL_V(shader, 0);3502return shader->vertex_input_mask;3503}35043505/******************/3506/**** UNIFORMS ****/3507/******************/35083509RID RenderingDevice::uniform_buffer_create(uint32_t p_size_bytes, Span<uint8_t> p_data, BitField<BufferCreationBits> p_creation_bits) {3510ERR_FAIL_COND_V(p_data.size() && (uint32_t)p_data.size() != p_size_bytes, RID());35113512Buffer buffer;3513buffer.size = p_size_bytes;3514buffer.usage = (RDD::BUFFER_USAGE_TRANSFER_TO_BIT | RDD::BUFFER_USAGE_UNIFORM_BIT);3515if (p_creation_bits.has_flag(BUFFER_CREATION_DEVICE_ADDRESS_BIT)) {3516buffer.usage.set_flag(RDD::BUFFER_USAGE_DEVICE_ADDRESS_BIT);3517}3518buffer.driver_id = driver->buffer_create(buffer.size, buffer.usage, RDD::MEMORY_ALLOCATION_TYPE_GPU);3519ERR_FAIL_COND_V(!buffer.driver_id, RID());35203521// Uniform buffers are assumed to be immutable unless they don't have initial data.3522if (p_data.is_empty()) {3523buffer.draw_tracker = RDG::resource_tracker_create();3524buffer.draw_tracker->buffer_driver_id = buffer.driver_id;3525}35263527if (p_data.size()) {3528_buffer_initialize(&buffer, p_data);3529}35303531_THREAD_SAFE_LOCK_3532buffer_memory += buffer.size;3533_THREAD_SAFE_UNLOCK_35343535RID id = uniform_buffer_owner.make_rid(buffer);3536#ifdef DEV_ENABLED3537set_resource_name(id, "RID:" + itos(id.get_id()));3538#endif3539return id;3540}35413542void RenderingDevice::_uniform_set_update_shared(UniformSet *p_uniform_set) {3543for (UniformSet::SharedTexture shared : p_uniform_set->shared_textures_to_update) {3544Texture *texture = texture_owner.get_or_null(shared.texture);3545ERR_CONTINUE(texture == nullptr);3546_texture_update_shared_fallback(shared.texture, texture, shared.writing);3547}3548}35493550RID RenderingDevice::uniform_set_create(const VectorView<RD::Uniform> &p_uniforms, RID p_shader, uint32_t p_shader_set, bool p_linear_pool) {3551_THREAD_SAFE_METHOD_35523553ERR_FAIL_COND_V(p_uniforms.size() == 0, RID());35543555Shader *shader = shader_owner.get_or_null(p_shader);3556ERR_FAIL_NULL_V(shader, RID());35573558ERR_FAIL_COND_V_MSG(p_shader_set >= (uint32_t)shader->uniform_sets.size() || shader->uniform_sets[p_shader_set].is_empty(), RID(),3559"Desired set (" + itos(p_shader_set) + ") not used by shader.");3560// See that all sets in shader are satisfied.35613562const Vector<ShaderUniform> &set = shader->uniform_sets[p_shader_set];35633564uint32_t uniform_count = p_uniforms.size();3565const Uniform *uniforms = p_uniforms.ptr();35663567uint32_t set_uniform_count = set.size();3568const ShaderUniform *set_uniforms = set.ptr();35693570LocalVector<RDD::BoundUniform> driver_uniforms;3571driver_uniforms.resize(set_uniform_count);35723573// Used for verification to make sure a uniform set does not use a framebuffer bound texture.3574LocalVector<UniformSet::AttachableTexture> attachable_textures;3575Vector<RDG::ResourceTracker *> draw_trackers;3576Vector<RDG::ResourceUsage> draw_trackers_usage;3577HashMap<RID, RDG::ResourceUsage> untracked_usage;3578Vector<UniformSet::SharedTexture> shared_textures_to_update;35793580for (uint32_t i = 0; i < set_uniform_count; i++) {3581const ShaderUniform &set_uniform = set_uniforms[i];3582int uniform_idx = -1;3583for (int j = 0; j < (int)uniform_count; j++) {3584if (uniforms[j].binding == set_uniform.binding) {3585uniform_idx = j;3586break;3587}3588}3589ERR_FAIL_COND_V_MSG(uniform_idx == -1, RID(),3590"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.");35913592const Uniform &uniform = uniforms[uniform_idx];35933594ERR_FAIL_INDEX_V(uniform.uniform_type, RD::UNIFORM_TYPE_MAX, RID());3595ERR_FAIL_COND_V_MSG(uniform.uniform_type != set_uniform.type, RID(),3596"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] + "'.");35973598RDD::BoundUniform &driver_uniform = driver_uniforms[i];3599driver_uniform.type = uniform.uniform_type;3600driver_uniform.binding = uniform.binding;36013602// Mark immutable samplers to be skipped when creating uniform set.3603driver_uniform.immutable_sampler = uniform.immutable_sampler;36043605switch (uniform.uniform_type) {3606case UNIFORM_TYPE_SAMPLER: {3607if (uniform.get_id_count() != (uint32_t)set_uniform.length) {3608if (set_uniform.length > 1) {3609ERR_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()) + ").");3610} else {3611ERR_FAIL_V_MSG(RID(), "Sampler (binding: " + itos(uniform.binding) + ") should provide one ID referencing a sampler (IDs provided: " + itos(uniform.get_id_count()) + ").");3612}3613}36143615for (uint32_t j = 0; j < uniform.get_id_count(); j++) {3616RDD::SamplerID *sampler_driver_id = sampler_owner.get_or_null(uniform.get_id(j));3617ERR_FAIL_NULL_V_MSG(sampler_driver_id, RID(), "Sampler (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") is not a valid sampler.");36183619driver_uniform.ids.push_back(*sampler_driver_id);3620}3621} break;3622case UNIFORM_TYPE_SAMPLER_WITH_TEXTURE: {3623if (uniform.get_id_count() != (uint32_t)set_uniform.length * 2) {3624if (set_uniform.length > 1) {3625ERR_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()) + ").");3626} else {3627ERR_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()) + ").");3628}3629}36303631for (uint32_t j = 0; j < uniform.get_id_count(); j += 2) {3632RDD::SamplerID *sampler_driver_id = sampler_owner.get_or_null(uniform.get_id(j + 0));3633ERR_FAIL_NULL_V_MSG(sampler_driver_id, RID(), "SamplerBuffer (binding: " + itos(uniform.binding) + ", index " + itos(j + 1) + ") is not a valid sampler.");36343635RID texture_id = uniform.get_id(j + 1);3636Texture *texture = texture_owner.get_or_null(texture_id);3637ERR_FAIL_NULL_V_MSG(texture, RID(), "Texture (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") is not a valid texture.");36383639ERR_FAIL_COND_V_MSG(!(texture->usage_flags & TEXTURE_USAGE_SAMPLING_BIT), RID(),3640"Texture (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") needs the TEXTURE_USAGE_SAMPLING_BIT usage flag set in order to be used as uniform.");36413642if ((texture->usage_flags & (TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | TEXTURE_USAGE_INPUT_ATTACHMENT_BIT))) {3643UniformSet::AttachableTexture attachable_texture;3644attachable_texture.bind = set_uniform.binding;3645attachable_texture.texture = texture->owner.is_valid() ? texture->owner : uniform.get_id(j + 1);3646attachable_textures.push_back(attachable_texture);3647}36483649RDD::TextureID driver_id = texture->driver_id;3650RDG::ResourceTracker *tracker = texture->draw_tracker;3651if (texture->shared_fallback != nullptr && texture->shared_fallback->texture.id != 0) {3652driver_id = texture->shared_fallback->texture;3653tracker = texture->shared_fallback->texture_tracker;3654shared_textures_to_update.push_back({ false, texture_id });3655}36563657if (tracker != nullptr) {3658draw_trackers.push_back(tracker);3659draw_trackers_usage.push_back(RDG::RESOURCE_USAGE_TEXTURE_SAMPLE);3660} else {3661untracked_usage[texture_id] = RDG::RESOURCE_USAGE_TEXTURE_SAMPLE;3662}36633664DEV_ASSERT(!texture->owner.is_valid() || texture_owner.get_or_null(texture->owner));36653666driver_uniform.ids.push_back(*sampler_driver_id);3667driver_uniform.ids.push_back(driver_id);3668_check_transfer_worker_texture(texture);3669}3670} break;3671case UNIFORM_TYPE_TEXTURE: {3672if (uniform.get_id_count() != (uint32_t)set_uniform.length) {3673if (set_uniform.length > 1) {3674ERR_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()) + ").");3675} else {3676ERR_FAIL_V_MSG(RID(), "Texture (binding: " + itos(uniform.binding) + ") should provide one ID referencing a texture (IDs provided: " + itos(uniform.get_id_count()) + ").");3677}3678}36793680for (uint32_t j = 0; j < uniform.get_id_count(); j++) {3681RID texture_id = uniform.get_id(j);3682Texture *texture = texture_owner.get_or_null(texture_id);3683ERR_FAIL_NULL_V_MSG(texture, RID(), "Texture (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") is not a valid texture.");36843685ERR_FAIL_COND_V_MSG(!(texture->usage_flags & TEXTURE_USAGE_SAMPLING_BIT), RID(),3686"Texture (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") needs the TEXTURE_USAGE_SAMPLING_BIT usage flag set in order to be used as uniform.");36873688if ((texture->usage_flags & (TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | TEXTURE_USAGE_INPUT_ATTACHMENT_BIT))) {3689UniformSet::AttachableTexture attachable_texture;3690attachable_texture.bind = set_uniform.binding;3691attachable_texture.texture = texture->owner.is_valid() ? texture->owner : uniform.get_id(j);3692attachable_textures.push_back(attachable_texture);3693}36943695RDD::TextureID driver_id = texture->driver_id;3696RDG::ResourceTracker *tracker = texture->draw_tracker;3697if (texture->shared_fallback != nullptr && texture->shared_fallback->texture.id != 0) {3698driver_id = texture->shared_fallback->texture;3699tracker = texture->shared_fallback->texture_tracker;3700shared_textures_to_update.push_back({ false, texture_id });3701}37023703if (tracker != nullptr) {3704draw_trackers.push_back(tracker);3705draw_trackers_usage.push_back(RDG::RESOURCE_USAGE_TEXTURE_SAMPLE);3706} else {3707untracked_usage[texture_id] = RDG::RESOURCE_USAGE_TEXTURE_SAMPLE;3708}37093710DEV_ASSERT(!texture->owner.is_valid() || texture_owner.get_or_null(texture->owner));37113712driver_uniform.ids.push_back(driver_id);3713_check_transfer_worker_texture(texture);3714}3715} break;3716case UNIFORM_TYPE_IMAGE: {3717if (uniform.get_id_count() != (uint32_t)set_uniform.length) {3718if (set_uniform.length > 1) {3719ERR_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()) + ").");3720} else {3721ERR_FAIL_V_MSG(RID(), "Image (binding: " + itos(uniform.binding) + ") should provide one ID referencing a texture (IDs provided: " + itos(uniform.get_id_count()) + ").");3722}3723}37243725for (uint32_t j = 0; j < uniform.get_id_count(); j++) {3726RID texture_id = uniform.get_id(j);3727Texture *texture = texture_owner.get_or_null(texture_id);37283729ERR_FAIL_NULL_V_MSG(texture, RID(),3730"Image (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") is not a valid texture.");37313732ERR_FAIL_COND_V_MSG(!(texture->usage_flags & TEXTURE_USAGE_STORAGE_BIT), RID(),3733"Image (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") needs the TEXTURE_USAGE_STORAGE_BIT usage flag set in order to be used as uniform.");37343735if (texture->owner.is_null() && texture->shared_fallback != nullptr) {3736shared_textures_to_update.push_back({ true, texture_id });3737}37383739if (_texture_make_mutable(texture, texture_id)) {3740// The texture must be mutable as a layout transition will be required.3741draw_graph.add_synchronization();3742}37433744if (texture->draw_tracker != nullptr) {3745draw_trackers.push_back(texture->draw_tracker);37463747if (set_uniform.writable) {3748draw_trackers_usage.push_back(RDG::RESOURCE_USAGE_STORAGE_IMAGE_READ_WRITE);3749} else {3750draw_trackers_usage.push_back(RDG::RESOURCE_USAGE_STORAGE_IMAGE_READ);3751}3752}37533754DEV_ASSERT(!texture->owner.is_valid() || texture_owner.get_or_null(texture->owner));37553756driver_uniform.ids.push_back(texture->driver_id);3757_check_transfer_worker_texture(texture);3758}3759} break;3760case UNIFORM_TYPE_TEXTURE_BUFFER: {3761if (uniform.get_id_count() != (uint32_t)set_uniform.length) {3762if (set_uniform.length > 1) {3763ERR_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()) + ").");3764} else {3765ERR_FAIL_V_MSG(RID(), "Buffer (binding: " + itos(uniform.binding) + ") should provide one ID referencing a texture buffer (IDs provided: " + itos(uniform.get_id_count()) + ").");3766}3767}37683769for (uint32_t j = 0; j < uniform.get_id_count(); j++) {3770RID buffer_id = uniform.get_id(j);3771Buffer *buffer = texture_buffer_owner.get_or_null(buffer_id);3772ERR_FAIL_NULL_V_MSG(buffer, RID(), "Texture Buffer (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") is not a valid texture buffer.");37733774if (set_uniform.writable && _buffer_make_mutable(buffer, buffer_id)) {3775// The buffer must be mutable if it's used for writing.3776draw_graph.add_synchronization();3777}37783779if (buffer->draw_tracker != nullptr) {3780draw_trackers.push_back(buffer->draw_tracker);37813782if (set_uniform.writable) {3783draw_trackers_usage.push_back(RDG::RESOURCE_USAGE_TEXTURE_BUFFER_READ_WRITE);3784} else {3785draw_trackers_usage.push_back(RDG::RESOURCE_USAGE_TEXTURE_BUFFER_READ);3786}3787} else {3788untracked_usage[buffer_id] = RDG::RESOURCE_USAGE_TEXTURE_BUFFER_READ;3789}37903791driver_uniform.ids.push_back(buffer->driver_id);3792_check_transfer_worker_buffer(buffer);3793}3794} break;3795case UNIFORM_TYPE_SAMPLER_WITH_TEXTURE_BUFFER: {3796if (uniform.get_id_count() != (uint32_t)set_uniform.length * 2) {3797if (set_uniform.length > 1) {3798ERR_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()) + ").");3799} else {3800ERR_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()) + ").");3801}3802}38033804for (uint32_t j = 0; j < uniform.get_id_count(); j += 2) {3805RDD::SamplerID *sampler_driver_id = sampler_owner.get_or_null(uniform.get_id(j + 0));3806ERR_FAIL_NULL_V_MSG(sampler_driver_id, RID(), "SamplerBuffer (binding: " + itos(uniform.binding) + ", index " + itos(j + 1) + ") is not a valid sampler.");38073808RID buffer_id = uniform.get_id(j + 1);3809Buffer *buffer = texture_buffer_owner.get_or_null(buffer_id);3810ERR_FAIL_NULL_V_MSG(buffer, RID(), "SamplerBuffer (binding: " + itos(uniform.binding) + ", index " + itos(j + 1) + ") is not a valid texture buffer.");38113812if (buffer->draw_tracker != nullptr) {3813draw_trackers.push_back(buffer->draw_tracker);3814draw_trackers_usage.push_back(RDG::RESOURCE_USAGE_TEXTURE_BUFFER_READ);3815} else {3816untracked_usage[buffer_id] = RDG::RESOURCE_USAGE_TEXTURE_BUFFER_READ;3817}38183819driver_uniform.ids.push_back(*sampler_driver_id);3820driver_uniform.ids.push_back(buffer->driver_id);3821_check_transfer_worker_buffer(buffer);3822}3823} break;3824case UNIFORM_TYPE_IMAGE_BUFFER: {3825// Todo.3826} break;3827case UNIFORM_TYPE_UNIFORM_BUFFER: {3828ERR_FAIL_COND_V_MSG(uniform.get_id_count() != 1, RID(),3829"Uniform buffer supplied (binding: " + itos(uniform.binding) + ") must provide one ID (" + itos(uniform.get_id_count()) + " provided).");38303831RID buffer_id = uniform.get_id(0);3832Buffer *buffer = uniform_buffer_owner.get_or_null(buffer_id);3833ERR_FAIL_NULL_V_MSG(buffer, RID(), "Uniform buffer supplied (binding: " + itos(uniform.binding) + ") is invalid.");38343835ERR_FAIL_COND_V_MSG(buffer->size < (uint32_t)set_uniform.length, RID(),3836"Uniform buffer supplied (binding: " + itos(uniform.binding) + ") size (" + itos(buffer->size) + ") is smaller than size of shader uniform: (" + itos(set_uniform.length) + ").");38373838if (buffer->draw_tracker != nullptr) {3839draw_trackers.push_back(buffer->draw_tracker);3840draw_trackers_usage.push_back(RDG::RESOURCE_USAGE_UNIFORM_BUFFER_READ);3841} else {3842untracked_usage[buffer_id] = RDG::RESOURCE_USAGE_UNIFORM_BUFFER_READ;3843}38443845driver_uniform.ids.push_back(buffer->driver_id);3846_check_transfer_worker_buffer(buffer);3847} break;3848case UNIFORM_TYPE_STORAGE_BUFFER: {3849ERR_FAIL_COND_V_MSG(uniform.get_id_count() != 1, RID(),3850"Storage buffer supplied (binding: " + itos(uniform.binding) + ") must provide one ID (" + itos(uniform.get_id_count()) + " provided).");38513852Buffer *buffer = nullptr;38533854RID buffer_id = uniform.get_id(0);3855if (storage_buffer_owner.owns(buffer_id)) {3856buffer = storage_buffer_owner.get_or_null(buffer_id);3857} else if (vertex_buffer_owner.owns(buffer_id)) {3858buffer = vertex_buffer_owner.get_or_null(buffer_id);38593860ERR_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.");3861}3862ERR_FAIL_NULL_V_MSG(buffer, RID(), "Storage buffer supplied (binding: " + itos(uniform.binding) + ") is invalid.");38633864// If 0, then it's sized on link time.3865ERR_FAIL_COND_V_MSG(set_uniform.length > 0 && buffer->size != (uint32_t)set_uniform.length, RID(),3866"Storage buffer supplied (binding: " + itos(uniform.binding) + ") size (" + itos(buffer->size) + ") does not match size of shader uniform: (" + itos(set_uniform.length) + ").");38673868if (set_uniform.writable && _buffer_make_mutable(buffer, buffer_id)) {3869// The buffer must be mutable if it's used for writing.3870draw_graph.add_synchronization();3871}38723873if (buffer->draw_tracker != nullptr) {3874draw_trackers.push_back(buffer->draw_tracker);38753876if (set_uniform.writable) {3877draw_trackers_usage.push_back(RDG::RESOURCE_USAGE_STORAGE_BUFFER_READ_WRITE);3878} else {3879draw_trackers_usage.push_back(RDG::RESOURCE_USAGE_STORAGE_BUFFER_READ);3880}3881} else {3882untracked_usage[buffer_id] = RDG::RESOURCE_USAGE_STORAGE_BUFFER_READ;3883}38843885driver_uniform.ids.push_back(buffer->driver_id);3886_check_transfer_worker_buffer(buffer);3887} break;3888case UNIFORM_TYPE_INPUT_ATTACHMENT: {3889ERR_FAIL_COND_V_MSG(shader->is_compute, RID(), "InputAttachment (binding: " + itos(uniform.binding) + ") supplied for compute shader (this is not allowed).");38903891if (uniform.get_id_count() != (uint32_t)set_uniform.length) {3892if (set_uniform.length > 1) {3893ERR_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()) + ").");3894} else {3895ERR_FAIL_V_MSG(RID(), "InputAttachment (binding: " + itos(uniform.binding) + ") should provide one ID referencing a texture (IDs provided: " + itos(uniform.get_id_count()) + ").");3896}3897}38983899for (uint32_t j = 0; j < uniform.get_id_count(); j++) {3900RID texture_id = uniform.get_id(j);3901Texture *texture = texture_owner.get_or_null(texture_id);39023903ERR_FAIL_NULL_V_MSG(texture, RID(),3904"InputAttachment (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") is not a valid texture.");39053906ERR_FAIL_COND_V_MSG(!(texture->usage_flags & TEXTURE_USAGE_SAMPLING_BIT), RID(),3907"InputAttachment (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") needs the TEXTURE_USAGE_SAMPLING_BIT usage flag set in order to be used as uniform.");39083909DEV_ASSERT(!texture->owner.is_valid() || texture_owner.get_or_null(texture->owner));39103911driver_uniform.ids.push_back(texture->driver_id);3912_check_transfer_worker_texture(texture);3913}3914} break;3915default: {3916}3917}3918}39193920RDD::UniformSetID driver_uniform_set = driver->uniform_set_create(driver_uniforms, shader->driver_id, p_shader_set, p_linear_pool ? frame : -1);3921ERR_FAIL_COND_V(!driver_uniform_set, RID());39223923UniformSet uniform_set;3924uniform_set.driver_id = driver_uniform_set;3925uniform_set.format = shader->set_formats[p_shader_set];3926uniform_set.attachable_textures = attachable_textures;3927uniform_set.draw_trackers = draw_trackers;3928uniform_set.draw_trackers_usage = draw_trackers_usage;3929uniform_set.untracked_usage = untracked_usage;3930uniform_set.shared_textures_to_update = shared_textures_to_update;3931uniform_set.shader_set = p_shader_set;3932uniform_set.shader_id = p_shader;39333934RID id = uniform_set_owner.make_rid(uniform_set);3935#ifdef DEV_ENABLED3936set_resource_name(id, "RID:" + itos(id.get_id()));3937#endif3938// Add dependencies.3939_add_dependency(id, p_shader);3940for (uint32_t i = 0; i < uniform_count; i++) {3941const Uniform &uniform = uniforms[i];3942int id_count = uniform.get_id_count();3943for (int j = 0; j < id_count; j++) {3944_add_dependency(id, uniform.get_id(j));3945}3946}39473948return id;3949}39503951bool RenderingDevice::uniform_set_is_valid(RID p_uniform_set) {3952_THREAD_SAFE_METHOD_39533954return uniform_set_owner.owns(p_uniform_set);3955}39563957void RenderingDevice::uniform_set_set_invalidation_callback(RID p_uniform_set, InvalidationCallback p_callback, void *p_userdata) {3958_THREAD_SAFE_METHOD_39593960UniformSet *us = uniform_set_owner.get_or_null(p_uniform_set);3961ERR_FAIL_NULL(us);3962us->invalidated_callback = p_callback;3963us->invalidated_callback_userdata = p_userdata;3964}39653966bool RenderingDevice::uniform_sets_have_linear_pools() const {3967return driver->uniform_sets_have_linear_pools();3968}39693970/*******************/3971/**** PIPELINES ****/3972/*******************/39733974RID 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) {3975// Needs a shader.3976Shader *shader = shader_owner.get_or_null(p_shader);3977ERR_FAIL_NULL_V(shader, RID());3978ERR_FAIL_COND_V_MSG(shader->is_compute, RID(), "Compute shaders can't be used in render pipelines");39793980// Validate pre-raster shader. One of stages must be vertex shader or mesh shader (not implemented yet).3981ERR_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.");39823983FramebufferFormat fb_format;3984{3985_THREAD_SAFE_METHOD_39863987if (p_framebuffer_format == INVALID_ID) {3988// If nothing provided, use an empty one (no attachments).3989p_framebuffer_format = framebuffer_format_create(Vector<AttachmentFormat>());3990}3991ERR_FAIL_COND_V(!framebuffer_formats.has(p_framebuffer_format), RID());3992fb_format = framebuffer_formats[p_framebuffer_format];3993}39943995// Validate shader vs. framebuffer.3996{3997ERR_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");3998const FramebufferPass &pass = fb_format.E->key().passes[p_for_render_pass];3999uint32_t output_mask = 0;4000for (int i = 0; i < pass.color_attachments.size(); i++) {4001if (pass.color_attachments[i] != ATTACHMENT_UNUSED) {4002output_mask |= 1 << i;4003}4004}4005ERR_FAIL_COND_V_MSG(shader->fragment_output_mask != output_mask, RID(),4006"Mismatch fragment shader output mask (" + itos(shader->fragment_output_mask) + ") and framebuffer color output mask (" + itos(output_mask) + ") when binding both in render pipeline.");4007}40084009RDD::VertexFormatID driver_vertex_format;4010if (p_vertex_format != INVALID_ID) {4011// Uses vertices, else it does not.4012ERR_FAIL_COND_V(!vertex_formats.has(p_vertex_format), RID());4013const VertexDescriptionCache &vd = vertex_formats[p_vertex_format];4014driver_vertex_format = vertex_formats[p_vertex_format].driver_id;40154016// Validate with inputs.4017for (uint32_t i = 0; i < 64; i++) {4018if (!(shader->vertex_input_mask & ((uint64_t)1) << i)) {4019continue;4020}4021bool found = false;4022for (int j = 0; j < vd.vertex_formats.size(); j++) {4023if (vd.vertex_formats[j].location == i) {4024found = true;4025break;4026}4027}40284029ERR_FAIL_COND_V_MSG(!found, RID(),4030"Shader vertex input location (" + itos(i) + ") not provided in vertex input description for pipeline creation.");4031}40324033} else {4034ERR_FAIL_COND_V_MSG(shader->vertex_input_mask != 0, RID(),4035"Shader contains vertex inputs, but no vertex input description was provided for pipeline creation.");4036}40374038ERR_FAIL_INDEX_V(p_render_primitive, RENDER_PRIMITIVE_MAX, RID());40394040ERR_FAIL_INDEX_V(p_rasterization_state.cull_mode, 3, RID());40414042if (p_multisample_state.sample_mask.size()) {4043// Use sample mask.4044ERR_FAIL_COND_V((int)TEXTURE_SAMPLES_COUNT[p_multisample_state.sample_count] != p_multisample_state.sample_mask.size(), RID());4045}40464047ERR_FAIL_INDEX_V(p_depth_stencil_state.depth_compare_operator, COMPARE_OP_MAX, RID());40484049ERR_FAIL_INDEX_V(p_depth_stencil_state.front_op.fail, STENCIL_OP_MAX, RID());4050ERR_FAIL_INDEX_V(p_depth_stencil_state.front_op.pass, STENCIL_OP_MAX, RID());4051ERR_FAIL_INDEX_V(p_depth_stencil_state.front_op.depth_fail, STENCIL_OP_MAX, RID());4052ERR_FAIL_INDEX_V(p_depth_stencil_state.front_op.compare, COMPARE_OP_MAX, RID());40534054ERR_FAIL_INDEX_V(p_depth_stencil_state.back_op.fail, STENCIL_OP_MAX, RID());4055ERR_FAIL_INDEX_V(p_depth_stencil_state.back_op.pass, STENCIL_OP_MAX, RID());4056ERR_FAIL_INDEX_V(p_depth_stencil_state.back_op.depth_fail, STENCIL_OP_MAX, RID());4057ERR_FAIL_INDEX_V(p_depth_stencil_state.back_op.compare, COMPARE_OP_MAX, RID());40584059ERR_FAIL_INDEX_V(p_blend_state.logic_op, LOGIC_OP_MAX, RID());40604061const FramebufferPass &pass = fb_format.E->key().passes[p_for_render_pass];4062ERR_FAIL_COND_V(p_blend_state.attachments.size() < pass.color_attachments.size(), RID());4063for (int i = 0; i < pass.color_attachments.size(); i++) {4064if (pass.color_attachments[i] != ATTACHMENT_UNUSED) {4065ERR_FAIL_INDEX_V(p_blend_state.attachments[i].src_color_blend_factor, BLEND_FACTOR_MAX, RID());4066ERR_FAIL_INDEX_V(p_blend_state.attachments[i].dst_color_blend_factor, BLEND_FACTOR_MAX, RID());4067ERR_FAIL_INDEX_V(p_blend_state.attachments[i].color_blend_op, BLEND_OP_MAX, RID());40684069ERR_FAIL_INDEX_V(p_blend_state.attachments[i].src_alpha_blend_factor, BLEND_FACTOR_MAX, RID());4070ERR_FAIL_INDEX_V(p_blend_state.attachments[i].dst_alpha_blend_factor, BLEND_FACTOR_MAX, RID());4071ERR_FAIL_INDEX_V(p_blend_state.attachments[i].alpha_blend_op, BLEND_OP_MAX, RID());4072}4073}40744075for (int i = 0; i < shader->specialization_constants.size(); i++) {4076const ShaderSpecializationConstant &sc = shader->specialization_constants[i];4077for (int j = 0; j < p_specialization_constants.size(); j++) {4078const PipelineSpecializationConstant &psc = p_specialization_constants[j];4079if (psc.constant_id == sc.constant_id) {4080ERR_FAIL_COND_V_MSG(psc.type != sc.type, RID(), "Specialization constant provided for id (" + itos(sc.constant_id) + ") is of the wrong type.");4081break;4082}4083}4084}40854086RenderPipeline pipeline;4087pipeline.driver_id = driver->render_pipeline_create(4088shader->driver_id,4089driver_vertex_format,4090p_render_primitive,4091p_rasterization_state,4092p_multisample_state,4093p_depth_stencil_state,4094p_blend_state,4095pass.color_attachments,4096p_dynamic_state_flags,4097fb_format.render_pass,4098p_for_render_pass,4099p_specialization_constants);4100ERR_FAIL_COND_V(!pipeline.driver_id, RID());41014102if (pipeline_cache_enabled) {4103_update_pipeline_cache();4104}41054106pipeline.shader = p_shader;4107pipeline.shader_driver_id = shader->driver_id;4108pipeline.shader_layout_hash = shader->layout_hash;4109pipeline.set_formats = shader->set_formats;4110pipeline.push_constant_size = shader->push_constant_size;4111pipeline.stage_bits = shader->stage_bits;41124113#ifdef DEBUG_ENABLED4114pipeline.validation.dynamic_state = p_dynamic_state_flags;4115pipeline.validation.framebuffer_format = p_framebuffer_format;4116pipeline.validation.render_pass = p_for_render_pass;4117pipeline.validation.vertex_format = p_vertex_format;4118pipeline.validation.uses_restart_indices = p_render_primitive == RENDER_PRIMITIVE_TRIANGLE_STRIPS_WITH_RESTART_INDEX;41194120static const uint32_t primitive_divisor[RENDER_PRIMITIVE_MAX] = {41211, 2, 1, 1, 1, 3, 1, 1, 1, 1, 14122};4123pipeline.validation.primitive_divisor = primitive_divisor[p_render_primitive];4124static const uint32_t primitive_minimum[RENDER_PRIMITIVE_MAX] = {41251,41262,41272,41282,41292,41303,41313,41323,41333,41343,41351,4136};4137pipeline.validation.primitive_minimum = primitive_minimum[p_render_primitive];4138#endif41394140// Create ID to associate with this pipeline.4141RID id = render_pipeline_owner.make_rid(pipeline);4142{4143_THREAD_SAFE_METHOD_41444145#ifdef DEV_ENABLED4146set_resource_name(id, "RID:" + itos(id.get_id()));4147#endif4148// Now add all the dependencies.4149_add_dependency(id, p_shader);4150}41514152return id;4153}41544155bool RenderingDevice::render_pipeline_is_valid(RID p_pipeline) {4156_THREAD_SAFE_METHOD_41574158return render_pipeline_owner.owns(p_pipeline);4159}41604161RID RenderingDevice::compute_pipeline_create(RID p_shader, const Vector<PipelineSpecializationConstant> &p_specialization_constants) {4162Shader *shader;41634164{4165_THREAD_SAFE_METHOD_41664167// Needs a shader.4168shader = shader_owner.get_or_null(p_shader);4169ERR_FAIL_NULL_V(shader, RID());41704171ERR_FAIL_COND_V_MSG(!shader->is_compute, RID(),4172"Non-compute shaders can't be used in compute pipelines");4173}41744175for (int i = 0; i < shader->specialization_constants.size(); i++) {4176const ShaderSpecializationConstant &sc = shader->specialization_constants[i];4177for (int j = 0; j < p_specialization_constants.size(); j++) {4178const PipelineSpecializationConstant &psc = p_specialization_constants[j];4179if (psc.constant_id == sc.constant_id) {4180ERR_FAIL_COND_V_MSG(psc.type != sc.type, RID(), "Specialization constant provided for id (" + itos(sc.constant_id) + ") is of the wrong type.");4181break;4182}4183}4184}41854186ComputePipeline pipeline;4187pipeline.driver_id = driver->compute_pipeline_create(shader->driver_id, p_specialization_constants);4188ERR_FAIL_COND_V(!pipeline.driver_id, RID());41894190if (pipeline_cache_enabled) {4191_update_pipeline_cache();4192}41934194pipeline.shader = p_shader;4195pipeline.shader_driver_id = shader->driver_id;4196pipeline.shader_layout_hash = shader->layout_hash;4197pipeline.set_formats = shader->set_formats;4198pipeline.push_constant_size = shader->push_constant_size;4199pipeline.local_group_size[0] = shader->compute_local_size[0];4200pipeline.local_group_size[1] = shader->compute_local_size[1];4201pipeline.local_group_size[2] = shader->compute_local_size[2];42024203// Create ID to associate with this pipeline.4204RID id = compute_pipeline_owner.make_rid(pipeline);4205{4206_THREAD_SAFE_METHOD_42074208#ifdef DEV_ENABLED4209set_resource_name(id, "RID:" + itos(id.get_id()));4210#endif4211// Now add all the dependencies.4212_add_dependency(id, p_shader);4213}42144215return id;4216}42174218bool RenderingDevice::compute_pipeline_is_valid(RID p_pipeline) {4219_THREAD_SAFE_METHOD_42204221return compute_pipeline_owner.owns(p_pipeline);4222}42234224/****************/4225/**** SCREEN ****/4226/****************/42274228uint32_t RenderingDevice::_get_swap_chain_desired_count() const {4229return MAX(2U, uint32_t(GLOBAL_GET_CACHED(uint32_t, "rendering/rendering_device/vsync/swapchain_image_count")));4230}42314232Error RenderingDevice::screen_create(DisplayServer::WindowID p_screen) {4233_THREAD_SAFE_METHOD_42344235RenderingContextDriver::SurfaceID surface = context->surface_get_from_window(p_screen);4236ERR_FAIL_COND_V_MSG(surface == 0, ERR_CANT_CREATE, "A surface was not created for the screen.");42374238HashMap<DisplayServer::WindowID, RDD::SwapChainID>::ConstIterator it = screen_swap_chains.find(p_screen);4239ERR_FAIL_COND_V_MSG(it != screen_swap_chains.end(), ERR_CANT_CREATE, "A swap chain was already created for the screen.");42404241RDD::SwapChainID swap_chain = driver->swap_chain_create(surface);4242ERR_FAIL_COND_V_MSG(swap_chain.id == 0, ERR_CANT_CREATE, "Unable to create swap chain.");42434244screen_swap_chains[p_screen] = swap_chain;42454246return OK;4247}42484249Error RenderingDevice::screen_prepare_for_drawing(DisplayServer::WindowID p_screen) {4250_THREAD_SAFE_METHOD_42514252// After submitting work, acquire the swapchain image(s).4253HashMap<DisplayServer::WindowID, RDD::SwapChainID>::ConstIterator it = screen_swap_chains.find(p_screen);4254ERR_FAIL_COND_V_MSG(it == screen_swap_chains.end(), ERR_CANT_CREATE, "A swap chain was not created for the screen.");42554256// Erase the framebuffer corresponding to this screen from the map in case any of the operations fail.4257screen_framebuffers.erase(p_screen);42584259// If this frame has already queued this swap chain for presentation, we present it and remove it from the pending list.4260uint32_t to_present_index = 0;4261while (to_present_index < frames[frame].swap_chains_to_present.size()) {4262if (frames[frame].swap_chains_to_present[to_present_index] == it->value) {4263driver->command_queue_execute_and_present(present_queue, {}, {}, {}, {}, it->value);4264frames[frame].swap_chains_to_present.remove_at(to_present_index);4265} else {4266to_present_index++;4267}4268}42694270bool resize_required = false;4271RDD::FramebufferID framebuffer = driver->swap_chain_acquire_framebuffer(main_queue, it->value, resize_required);4272if (resize_required) {4273// Flush everything so nothing can be using the swap chain before resizing it.4274_flush_and_stall_for_all_frames();42754276Error err = driver->swap_chain_resize(main_queue, it->value, _get_swap_chain_desired_count());4277if (err != OK) {4278// Resize is allowed to fail silently because the window can be minimized.4279return err;4280}42814282framebuffer = driver->swap_chain_acquire_framebuffer(main_queue, it->value, resize_required);4283}42844285if (framebuffer.id == 0) {4286// Some drivers like NVIDIA are fast enough to invalidate the swap chain between resizing and acquisition (GH-94104).4287// This typically occurs during continuous window resizing operations, especially if done quickly.4288// Allow this to fail silently since it has no visual consequences.4289return ERR_CANT_CREATE;4290}42914292// Store the framebuffer that will be used next to draw to this screen.4293screen_framebuffers[p_screen] = framebuffer;4294frames[frame].swap_chains_to_present.push_back(it->value);42954296return OK;4297}42984299int RenderingDevice::screen_get_width(DisplayServer::WindowID p_screen) const {4300_THREAD_SAFE_METHOD_43014302RenderingContextDriver::SurfaceID surface = context->surface_get_from_window(p_screen);4303ERR_FAIL_COND_V_MSG(surface == 0, 0, "A surface was not created for the screen.");4304return context->surface_get_width(surface);4305}43064307int RenderingDevice::screen_get_height(DisplayServer::WindowID p_screen) const {4308_THREAD_SAFE_METHOD_43094310RenderingContextDriver::SurfaceID surface = context->surface_get_from_window(p_screen);4311ERR_FAIL_COND_V_MSG(surface == 0, 0, "A surface was not created for the screen.");4312return context->surface_get_height(surface);4313}43144315int RenderingDevice::screen_get_pre_rotation_degrees(DisplayServer::WindowID p_screen) const {4316_THREAD_SAFE_METHOD_43174318HashMap<DisplayServer::WindowID, RDD::SwapChainID>::ConstIterator it = screen_swap_chains.find(p_screen);4319ERR_FAIL_COND_V_MSG(it == screen_swap_chains.end(), ERR_CANT_CREATE, "A swap chain was not created for the screen.");43204321return driver->swap_chain_get_pre_rotation_degrees(it->value);4322}43234324RenderingDevice::FramebufferFormatID RenderingDevice::screen_get_framebuffer_format(DisplayServer::WindowID p_screen) const {4325_THREAD_SAFE_METHOD_43264327HashMap<DisplayServer::WindowID, RDD::SwapChainID>::ConstIterator it = screen_swap_chains.find(p_screen);4328ERR_FAIL_COND_V_MSG(it == screen_swap_chains.end(), FAILED, "Screen was never prepared.");43294330DataFormat format = driver->swap_chain_get_format(it->value);4331ERR_FAIL_COND_V(format == DATA_FORMAT_MAX, INVALID_ID);43324333AttachmentFormat attachment;4334attachment.format = format;4335attachment.samples = TEXTURE_SAMPLES_1;4336attachment.usage_flags = TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;4337Vector<AttachmentFormat> screen_attachment;4338screen_attachment.push_back(attachment);4339return const_cast<RenderingDevice *>(this)->framebuffer_format_create(screen_attachment);4340}43414342Error RenderingDevice::screen_free(DisplayServer::WindowID p_screen) {4343_THREAD_SAFE_METHOD_43444345HashMap<DisplayServer::WindowID, RDD::SwapChainID>::ConstIterator it = screen_swap_chains.find(p_screen);4346ERR_FAIL_COND_V_MSG(it == screen_swap_chains.end(), FAILED, "Screen was never created.");43474348// Flush everything so nothing can be using the swap chain before erasing it.4349_flush_and_stall_for_all_frames();43504351const DisplayServer::WindowID screen = it->key;4352const RDD::SwapChainID swap_chain = it->value;4353driver->swap_chain_free(swap_chain);4354screen_framebuffers.erase(screen);4355screen_swap_chains.erase(screen);43564357return OK;4358}43594360/*******************/4361/**** DRAW LIST ****/4362/*******************/43634364RenderingDevice::DrawListID RenderingDevice::draw_list_begin_for_screen(DisplayServer::WindowID p_screen, const Color &p_clear_color) {4365ERR_RENDER_THREAD_GUARD_V(INVALID_ID);43664367ERR_FAIL_COND_V_MSG(draw_list.active, INVALID_ID, "Only one draw list can be active at the same time.");4368ERR_FAIL_COND_V_MSG(compute_list.active, INVALID_ID, "Only one draw/compute list can be active at the same time.");43694370RenderingContextDriver::SurfaceID surface = context->surface_get_from_window(p_screen);4371HashMap<DisplayServer::WindowID, RDD::SwapChainID>::ConstIterator sc_it = screen_swap_chains.find(p_screen);4372HashMap<DisplayServer::WindowID, RDD::FramebufferID>::ConstIterator fb_it = screen_framebuffers.find(p_screen);4373ERR_FAIL_COND_V_MSG(surface == 0, 0, "A surface was not created for the screen.");4374ERR_FAIL_COND_V_MSG(sc_it == screen_swap_chains.end(), INVALID_ID, "Screen was never prepared.");4375ERR_FAIL_COND_V_MSG(fb_it == screen_framebuffers.end(), INVALID_ID, "Framebuffer was never prepared.");43764377Rect2i viewport = Rect2i(0, 0, context->surface_get_width(surface), context->surface_get_height(surface));43784379_draw_list_start(viewport);4380#ifdef DEBUG_ENABLED4381draw_list_framebuffer_format = screen_get_framebuffer_format(p_screen);4382#endif4383draw_list_subpass_count = 1;43844385RDD::RenderPassClearValue clear_value;4386clear_value.color = p_clear_color;43874388RDD::RenderPassID render_pass = driver->swap_chain_get_render_pass(sc_it->value);4389draw_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);43904391draw_graph.add_draw_list_set_viewport(viewport);4392draw_graph.add_draw_list_set_scissor(viewport);43934394return int64_t(ID_TYPE_DRAW_LIST) << ID_BASE_SHIFT;4395}43964397RenderingDevice::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) {4398return draw_list_begin(p_framebuffer, p_draw_flags, p_clear_color_values, p_clear_depth_value, p_clear_stencil_value, p_region, p_breadcrumb);4399}44004401RenderingDevice::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) {4402ERR_RENDER_THREAD_GUARD_V(INVALID_ID);44034404ERR_FAIL_COND_V_MSG(draw_list.active, INVALID_ID, "Only one draw list can be active at the same time.");44054406Framebuffer *framebuffer = framebuffer_owner.get_or_null(p_framebuffer);4407ERR_FAIL_NULL_V(framebuffer, INVALID_ID);44084409const FramebufferFormatKey &framebuffer_key = framebuffer_formats[framebuffer->format_id].E->key();4410Point2i viewport_offset;4411Point2i viewport_size = framebuffer->size;44124413if (p_region != Rect2() && p_region != Rect2(Vector2(), viewport_size)) { // Check custom region.4414Rect2i viewport(viewport_offset, viewport_size);4415Rect2i regioni = p_region;4416if (!((regioni.position.x >= viewport.position.x) && (regioni.position.y >= viewport.position.y) &&4417((regioni.position.x + regioni.size.x) <= (viewport.position.x + viewport.size.x)) &&4418((regioni.position.y + regioni.size.y) <= (viewport.position.y + viewport.size.y)))) {4419ERR_FAIL_V_MSG(INVALID_ID, "When supplying a custom region, it must be contained within the framebuffer rectangle");4420}44214422viewport_offset = regioni.position;4423viewport_size = regioni.size;4424}44254426thread_local LocalVector<RDG::AttachmentOperation> operations;4427thread_local LocalVector<RDD::RenderPassClearValue> clear_values;4428thread_local LocalVector<RDG::ResourceTracker *> resource_trackers;4429thread_local LocalVector<RDG::ResourceUsage> resource_usages;4430BitField<RDD::PipelineStageBits> stages = {};4431operations.resize(framebuffer->texture_ids.size());4432clear_values.resize(framebuffer->texture_ids.size());4433resource_trackers.clear();4434resource_usages.clear();4435stages.clear();44364437uint32_t color_index = 0;4438for (int i = 0; i < framebuffer->texture_ids.size(); i++) {4439RID texture_rid = framebuffer->texture_ids[i];4440Texture *texture = texture_owner.get_or_null(texture_rid);4441if (texture == nullptr) {4442operations[i] = RDG::ATTACHMENT_OPERATION_DEFAULT;4443clear_values[i] = RDD::RenderPassClearValue();4444continue;4445}44464447// Indicate the texture will get modified for the shared texture fallback.4448_texture_update_shared_fallback(texture_rid, texture, true);44494450RDG::AttachmentOperation operation = RDG::ATTACHMENT_OPERATION_DEFAULT;4451RDD::RenderPassClearValue clear_value;4452if (framebuffer_key.vrs_attachment == i && (texture->usage_flags & TEXTURE_USAGE_VRS_ATTACHMENT_BIT)) {4453resource_trackers.push_back(texture->draw_tracker);4454resource_usages.push_back(_vrs_usage_from_method(framebuffer_key.vrs_method));4455stages.set_flag(_vrs_stages_from_method(framebuffer_key.vrs_method));4456} else if (texture->usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) {4457if (p_draw_flags.has_flag(DrawFlags(DRAW_CLEAR_COLOR_0 << color_index))) {4458ERR_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));4459operation = RDG::ATTACHMENT_OPERATION_CLEAR;4460clear_value.color = p_clear_color_values[color_index];4461} else if (p_draw_flags.has_flag(DrawFlags(DRAW_IGNORE_COLOR_0 << color_index))) {4462operation = RDG::ATTACHMENT_OPERATION_IGNORE;4463}44644465resource_trackers.push_back(texture->draw_tracker);4466resource_usages.push_back(RDG::RESOURCE_USAGE_ATTACHMENT_COLOR_READ_WRITE);4467stages.set_flag(RDD::PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);4468color_index++;4469} else if (texture->usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {4470if (p_draw_flags.has_flag(DRAW_CLEAR_DEPTH) || p_draw_flags.has_flag(DRAW_CLEAR_STENCIL)) {4471operation = RDG::ATTACHMENT_OPERATION_CLEAR;4472clear_value.depth = p_clear_depth_value;4473clear_value.stencil = p_clear_stencil_value;4474} else if (p_draw_flags.has_flag(DRAW_IGNORE_DEPTH) || p_draw_flags.has_flag(DRAW_IGNORE_STENCIL)) {4475operation = RDG::ATTACHMENT_OPERATION_IGNORE;4476}44774478resource_trackers.push_back(texture->draw_tracker);4479resource_usages.push_back(RDG::RESOURCE_USAGE_ATTACHMENT_DEPTH_STENCIL_READ_WRITE);4480stages.set_flag(RDD::PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT);4481stages.set_flag(RDD::PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT);4482}44834484operations[i] = operation;4485clear_values[i] = clear_value;4486}44874488draw_graph.add_draw_list_begin(framebuffer->framebuffer_cache, Rect2i(viewport_offset, viewport_size), operations, clear_values, stages, p_breadcrumb);4489draw_graph.add_draw_list_usages(resource_trackers, resource_usages);44904491// Mark textures as bound.4492draw_list_bound_textures.clear();44934494for (int i = 0; i < framebuffer->texture_ids.size(); i++) {4495Texture *texture = texture_owner.get_or_null(framebuffer->texture_ids[i]);4496if (texture == nullptr) {4497continue;4498}44994500texture->bound = true;4501draw_list_bound_textures.push_back(framebuffer->texture_ids[i]);4502}45034504_draw_list_start(Rect2i(viewport_offset, viewport_size));4505#ifdef DEBUG_ENABLED4506draw_list_framebuffer_format = framebuffer->format_id;4507#endif4508draw_list_current_subpass = 0;4509draw_list_subpass_count = framebuffer_key.passes.size();45104511Rect2i viewport_rect(viewport_offset, viewport_size);4512draw_graph.add_draw_list_set_viewport(viewport_rect);4513draw_graph.add_draw_list_set_scissor(viewport_rect);45144515return int64_t(ID_TYPE_DRAW_LIST) << ID_BASE_SHIFT;4516}45174518#ifndef DISABLE_DEPRECATED4519Error 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) {4520ERR_FAIL_V_MSG(ERR_UNAVAILABLE, "Deprecated. Split draw lists are used automatically by RenderingDevice.");4521}4522#endif45234524void RenderingDevice::draw_list_set_blend_constants(DrawListID p_list, const Color &p_color) {4525ERR_RENDER_THREAD_GUARD();45264527ERR_FAIL_COND(!draw_list.active);45284529draw_graph.add_draw_list_set_blend_constants(p_color);4530}45314532void RenderingDevice::draw_list_bind_render_pipeline(DrawListID p_list, RID p_render_pipeline) {4533ERR_RENDER_THREAD_GUARD();45344535ERR_FAIL_COND(!draw_list.active);45364537const RenderPipeline *pipeline = render_pipeline_owner.get_or_null(p_render_pipeline);4538ERR_FAIL_NULL(pipeline);4539#ifdef DEBUG_ENABLED4540ERR_FAIL_COND(pipeline->validation.framebuffer_format != draw_list_framebuffer_format && pipeline->validation.render_pass != draw_list_current_subpass);4541#endif45424543if (p_render_pipeline == draw_list.state.pipeline) {4544return; // Redundant state, return.4545}45464547draw_list.state.pipeline = p_render_pipeline;45484549draw_graph.add_draw_list_bind_pipeline(pipeline->driver_id, pipeline->stage_bits);45504551if (draw_list.state.pipeline_shader != pipeline->shader) {4552// Shader changed, so descriptor sets may become incompatible.45534554uint32_t pcount = pipeline->set_formats.size(); // Formats count in this pipeline.4555draw_list.state.set_count = MAX(draw_list.state.set_count, pcount);4556const uint32_t *pformats = pipeline->set_formats.ptr(); // Pipeline set formats.45574558uint32_t first_invalid_set = UINT32_MAX; // All valid by default.4559if (pipeline->push_constant_size != draw_list.state.pipeline_push_constant_size) {4560// All sets must be invalidated as the pipeline layout is not compatible if the push constant range is different.4561draw_list.state.pipeline_push_constant_size = pipeline->push_constant_size;4562first_invalid_set = 0;4563} else {4564switch (driver->api_trait_get(RDD::API_TRAIT_SHADER_CHANGE_INVALIDATION)) {4565case RDD::SHADER_CHANGE_INVALIDATION_ALL_BOUND_UNIFORM_SETS: {4566first_invalid_set = 0;4567} break;4568case RDD::SHADER_CHANGE_INVALIDATION_INCOMPATIBLE_SETS_PLUS_CASCADE: {4569for (uint32_t i = 0; i < pcount; i++) {4570if (draw_list.state.sets[i].pipeline_expected_format != pformats[i]) {4571first_invalid_set = i;4572break;4573}4574}4575} break;4576case RDD::SHADER_CHANGE_INVALIDATION_ALL_OR_NONE_ACCORDING_TO_LAYOUT_HASH: {4577if (draw_list.state.pipeline_shader_layout_hash != pipeline->shader_layout_hash) {4578first_invalid_set = 0;4579}4580} break;4581}4582}45834584if (pipeline->push_constant_size) {4585#ifdef DEBUG_ENABLED4586draw_list.validation.pipeline_push_constant_supplied = false;4587#endif4588}45894590for (uint32_t i = 0; i < pcount; i++) {4591draw_list.state.sets[i].bound = draw_list.state.sets[i].bound && i < first_invalid_set;4592draw_list.state.sets[i].pipeline_expected_format = pformats[i];4593}45944595for (uint32_t i = pcount; i < draw_list.state.set_count; i++) {4596// Unbind the ones above (not used) if exist.4597draw_list.state.sets[i].bound = false;4598}45994600draw_list.state.set_count = pcount; // Update set count.46014602draw_list.state.pipeline_shader = pipeline->shader;4603draw_list.state.pipeline_shader_driver_id = pipeline->shader_driver_id;4604draw_list.state.pipeline_shader_layout_hash = pipeline->shader_layout_hash;4605}46064607#ifdef DEBUG_ENABLED4608// Update render pass pipeline info.4609draw_list.validation.pipeline_active = true;4610draw_list.validation.pipeline_dynamic_state = pipeline->validation.dynamic_state;4611draw_list.validation.pipeline_vertex_format = pipeline->validation.vertex_format;4612draw_list.validation.pipeline_uses_restart_indices = pipeline->validation.uses_restart_indices;4613draw_list.validation.pipeline_primitive_divisor = pipeline->validation.primitive_divisor;4614draw_list.validation.pipeline_primitive_minimum = pipeline->validation.primitive_minimum;4615draw_list.validation.pipeline_push_constant_size = pipeline->push_constant_size;4616#endif4617}46184619void RenderingDevice::draw_list_bind_uniform_set(DrawListID p_list, RID p_uniform_set, uint32_t p_index) {4620ERR_RENDER_THREAD_GUARD();46214622#ifdef DEBUG_ENABLED4623ERR_FAIL_COND_MSG(p_index >= driver->limit_get(LIMIT_MAX_BOUND_UNIFORM_SETS) || p_index >= MAX_UNIFORM_SETS,4624"Attempting to bind a descriptor set (" + itos(p_index) + ") greater than what the hardware supports (" + itos(driver->limit_get(LIMIT_MAX_BOUND_UNIFORM_SETS)) + ").");4625#endif46264627ERR_FAIL_COND(!draw_list.active);46284629const UniformSet *uniform_set = uniform_set_owner.get_or_null(p_uniform_set);4630ERR_FAIL_NULL(uniform_set);46314632if (p_index > draw_list.state.set_count) {4633draw_list.state.set_count = p_index;4634}46354636draw_list.state.sets[p_index].uniform_set_driver_id = uniform_set->driver_id; // Update set pointer.4637draw_list.state.sets[p_index].bound = false; // Needs rebind.4638draw_list.state.sets[p_index].uniform_set_format = uniform_set->format;4639draw_list.state.sets[p_index].uniform_set = p_uniform_set;46404641#ifdef DEBUG_ENABLED4642{ // Validate that textures bound are not attached as framebuffer bindings.4643uint32_t attachable_count = uniform_set->attachable_textures.size();4644const UniformSet::AttachableTexture *attachable_ptr = uniform_set->attachable_textures.ptr();4645uint32_t bound_count = draw_list_bound_textures.size();4646const RID *bound_ptr = draw_list_bound_textures.ptr();4647for (uint32_t i = 0; i < attachable_count; i++) {4648for (uint32_t j = 0; j < bound_count; j++) {4649ERR_FAIL_COND_MSG(attachable_ptr[i].texture == bound_ptr[j],4650"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.");4651}4652}4653}4654#endif4655}46564657void RenderingDevice::draw_list_bind_vertex_array(DrawListID p_list, RID p_vertex_array) {4658ERR_RENDER_THREAD_GUARD();46594660ERR_FAIL_COND(!draw_list.active);46614662VertexArray *vertex_array = vertex_array_owner.get_or_null(p_vertex_array);4663ERR_FAIL_NULL(vertex_array);46644665if (draw_list.state.vertex_array == p_vertex_array) {4666return; // Already set.4667}46684669_check_transfer_worker_vertex_array(vertex_array);46704671draw_list.state.vertex_array = p_vertex_array;46724673#ifdef DEBUG_ENABLED4674draw_list.validation.vertex_format = vertex_array->description;4675draw_list.validation.vertex_max_instances_allowed = vertex_array->max_instances_allowed;4676#endif4677draw_list.validation.vertex_array_size = vertex_array->vertex_count;46784679draw_graph.add_draw_list_bind_vertex_buffers(vertex_array->buffers, vertex_array->offsets);46804681for (int i = 0; i < vertex_array->draw_trackers.size(); i++) {4682draw_graph.add_draw_list_usage(vertex_array->draw_trackers[i], RDG::RESOURCE_USAGE_VERTEX_BUFFER_READ);4683}4684}46854686void RenderingDevice::draw_list_bind_index_array(DrawListID p_list, RID p_index_array) {4687ERR_RENDER_THREAD_GUARD();46884689ERR_FAIL_COND(!draw_list.active);46904691IndexArray *index_array = index_array_owner.get_or_null(p_index_array);4692ERR_FAIL_NULL(index_array);46934694if (draw_list.state.index_array == p_index_array) {4695return; // Already set.4696}46974698_check_transfer_worker_index_array(index_array);46994700draw_list.state.index_array = p_index_array;4701#ifdef DEBUG_ENABLED4702draw_list.validation.index_array_max_index = index_array->max_index;4703#endif4704draw_list.validation.index_array_count = index_array->indices;47054706const uint64_t offset_bytes = index_array->offset * (index_array->format == INDEX_BUFFER_FORMAT_UINT16 ? sizeof(uint16_t) : sizeof(uint32_t));4707draw_graph.add_draw_list_bind_index_buffer(index_array->driver_id, index_array->format, offset_bytes);47084709if (index_array->draw_tracker != nullptr) {4710draw_graph.add_draw_list_usage(index_array->draw_tracker, RDG::RESOURCE_USAGE_INDEX_BUFFER_READ);4711}4712}47134714void RenderingDevice::draw_list_set_line_width(DrawListID p_list, float p_width) {4715ERR_RENDER_THREAD_GUARD();47164717ERR_FAIL_COND(!draw_list.active);47184719draw_graph.add_draw_list_set_line_width(p_width);4720}47214722void RenderingDevice::draw_list_set_push_constant(DrawListID p_list, const void *p_data, uint32_t p_data_size) {4723ERR_RENDER_THREAD_GUARD();47244725ERR_FAIL_COND(!draw_list.active);47264727#ifdef DEBUG_ENABLED4728ERR_FAIL_COND_MSG(p_data_size != draw_list.validation.pipeline_push_constant_size,4729"This render pipeline requires (" + itos(draw_list.validation.pipeline_push_constant_size) + ") bytes of push constant data, supplied: (" + itos(p_data_size) + ")");4730#endif47314732draw_graph.add_draw_list_set_push_constant(draw_list.state.pipeline_shader_driver_id, p_data, p_data_size);47334734#ifdef DEBUG_ENABLED4735draw_list.validation.pipeline_push_constant_supplied = true;4736#endif4737}47384739void RenderingDevice::draw_list_draw(DrawListID p_list, bool p_use_indices, uint32_t p_instances, uint32_t p_procedural_vertices) {4740ERR_RENDER_THREAD_GUARD();47414742ERR_FAIL_COND(!draw_list.active);47434744#ifdef DEBUG_ENABLED4745ERR_FAIL_COND_MSG(!draw_list.validation.pipeline_active,4746"No render pipeline was set before attempting to draw.");4747if (draw_list.validation.pipeline_vertex_format != INVALID_ID) {4748// Pipeline uses vertices, validate format.4749ERR_FAIL_COND_MSG(draw_list.validation.vertex_format == INVALID_ID,4750"No vertex array was bound, and render pipeline expects vertices.");4751// Make sure format is right.4752ERR_FAIL_COND_MSG(draw_list.validation.pipeline_vertex_format != draw_list.validation.vertex_format,4753"The vertex format used to create the pipeline does not match the vertex format bound.");4754// Make sure number of instances is valid.4755ERR_FAIL_COND_MSG(p_instances > draw_list.validation.vertex_max_instances_allowed,4756"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) + ").");4757}47584759if (draw_list.validation.pipeline_push_constant_size > 0) {4760// Using push constants, check that they were supplied.4761ERR_FAIL_COND_MSG(!draw_list.validation.pipeline_push_constant_supplied,4762"The shader in this pipeline requires a push constant to be set before drawing, but it's not present.");4763}47644765#endif47664767#ifdef DEBUG_ENABLED4768for (uint32_t i = 0; i < draw_list.state.set_count; i++) {4769if (draw_list.state.sets[i].pipeline_expected_format == 0) {4770// Nothing expected by this pipeline.4771continue;4772}47734774if (draw_list.state.sets[i].pipeline_expected_format != draw_list.state.sets[i].uniform_set_format) {4775if (draw_list.state.sets[i].uniform_set_format == 0) {4776ERR_FAIL_MSG("Uniforms were never supplied for set (" + itos(i) + ") at the time of drawing, which are required by the pipeline.");4777} else if (uniform_set_owner.owns(draw_list.state.sets[i].uniform_set)) {4778UniformSet *us = uniform_set_owner.get_or_null(draw_list.state.sets[i].uniform_set);4779ERR_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));4780} else {4781ERR_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));4782}4783}4784}4785#endif4786thread_local LocalVector<RDD::UniformSetID> valid_descriptor_ids;4787valid_descriptor_ids.clear();4788valid_descriptor_ids.resize(draw_list.state.set_count);4789uint32_t valid_set_count = 0;4790uint32_t first_set_index = 0;4791uint32_t last_set_index = 0;4792bool found_first_set = false;47934794for (uint32_t i = 0; i < draw_list.state.set_count; i++) {4795if (draw_list.state.sets[i].pipeline_expected_format == 0) {4796continue; // Nothing expected by this pipeline.4797}47984799if (!draw_list.state.sets[i].bound && !found_first_set) {4800first_set_index = i;4801found_first_set = true;4802}4803// Prepare descriptor sets if the API doesn't use pipeline barriers.4804if (!driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) {4805draw_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);4806}4807}48084809// Bind descriptor sets.4810for (uint32_t i = first_set_index; i < draw_list.state.set_count; i++) {4811if (draw_list.state.sets[i].pipeline_expected_format == 0) {4812continue; // Nothing expected by this pipeline.4813}48144815if (!draw_list.state.sets[i].bound) {4816// Batch contiguous descriptor sets in a single call.4817if (descriptor_set_batching) {4818// All good, see if this requires re-binding.4819if (i - last_set_index > 1) {4820// If the descriptor sets are not contiguous, bind the previous ones and start a new batch.4821draw_graph.add_draw_list_bind_uniform_sets(draw_list.state.pipeline_shader_driver_id, valid_descriptor_ids, first_set_index, valid_set_count);48224823first_set_index = i;4824valid_set_count = 1;4825valid_descriptor_ids[0] = draw_list.state.sets[i].uniform_set_driver_id;4826} else {4827// Otherwise, keep storing in the current batch.4828valid_descriptor_ids[valid_set_count] = draw_list.state.sets[i].uniform_set_driver_id;4829valid_set_count++;4830}48314832UniformSet *uniform_set = uniform_set_owner.get_or_null(draw_list.state.sets[i].uniform_set);4833_uniform_set_update_shared(uniform_set);4834draw_graph.add_draw_list_usages(uniform_set->draw_trackers, uniform_set->draw_trackers_usage);4835draw_list.state.sets[i].bound = true;48364837last_set_index = i;4838} else {4839draw_graph.add_draw_list_bind_uniform_set(draw_list.state.pipeline_shader_driver_id, draw_list.state.sets[i].uniform_set_driver_id, i);4840}4841}4842}48434844// Bind the remaining batch.4845if (descriptor_set_batching && valid_set_count > 0) {4846draw_graph.add_draw_list_bind_uniform_sets(draw_list.state.pipeline_shader_driver_id, valid_descriptor_ids, first_set_index, valid_set_count);4847}48484849if (p_use_indices) {4850#ifdef DEBUG_ENABLED4851ERR_FAIL_COND_MSG(p_procedural_vertices > 0,4852"Procedural vertices can't be used together with indices.");48534854ERR_FAIL_COND_MSG(!draw_list.validation.index_array_count,4855"Draw command requested indices, but no index buffer was set.");48564857ERR_FAIL_COND_MSG(draw_list.validation.pipeline_uses_restart_indices != draw_list.validation.index_buffer_uses_restart_indices,4858"The usage of restart indices in index buffer does not match the render primitive in the pipeline.");4859#endif4860uint32_t to_draw = draw_list.validation.index_array_count;48614862#ifdef DEBUG_ENABLED4863ERR_FAIL_COND_MSG(to_draw < draw_list.validation.pipeline_primitive_minimum,4864"Too few indices (" + itos(to_draw) + ") for the render primitive set in the render pipeline (" + itos(draw_list.validation.pipeline_primitive_minimum) + ").");48654866ERR_FAIL_COND_MSG((to_draw % draw_list.validation.pipeline_primitive_divisor) != 0,4867"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) + ").");4868#endif48694870draw_graph.add_draw_list_draw_indexed(to_draw, p_instances, 0);4871} else {4872uint32_t to_draw;48734874if (p_procedural_vertices > 0) {4875#ifdef DEBUG_ENABLED4876ERR_FAIL_COND_MSG(draw_list.validation.pipeline_vertex_format != INVALID_ID,4877"Procedural vertices requested, but pipeline expects a vertex array.");4878#endif4879to_draw = p_procedural_vertices;4880} else {4881#ifdef DEBUG_ENABLED4882ERR_FAIL_COND_MSG(draw_list.validation.pipeline_vertex_format == INVALID_ID,4883"Draw command lacks indices, but pipeline format does not use vertices.");4884#endif4885to_draw = draw_list.validation.vertex_array_size;4886}48874888#ifdef DEBUG_ENABLED4889ERR_FAIL_COND_MSG(to_draw < draw_list.validation.pipeline_primitive_minimum,4890"Too few vertices (" + itos(to_draw) + ") for the render primitive set in the render pipeline (" + itos(draw_list.validation.pipeline_primitive_minimum) + ").");48914892ERR_FAIL_COND_MSG((to_draw % draw_list.validation.pipeline_primitive_divisor) != 0,4893"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) + ").");4894#endif48954896draw_graph.add_draw_list_draw(to_draw, p_instances);4897}48984899draw_list.state.draw_count++;4900}49014902void 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) {4903ERR_RENDER_THREAD_GUARD();49044905ERR_FAIL_COND(!draw_list.active);49064907Buffer *buffer = storage_buffer_owner.get_or_null(p_buffer);4908ERR_FAIL_NULL(buffer);49094910ERR_FAIL_COND_MSG(!buffer->usage.has_flag(RDD::BUFFER_USAGE_INDIRECT_BIT), "Buffer provided was not created to do indirect dispatch.");49114912#ifdef DEBUG_ENABLED4913ERR_FAIL_COND_MSG(!draw_list.validation.pipeline_active,4914"No render pipeline was set before attempting to draw.");4915if (draw_list.validation.pipeline_vertex_format != INVALID_ID) {4916// Pipeline uses vertices, validate format.4917ERR_FAIL_COND_MSG(draw_list.validation.vertex_format == INVALID_ID,4918"No vertex array was bound, and render pipeline expects vertices.");4919// Make sure format is right.4920ERR_FAIL_COND_MSG(draw_list.validation.pipeline_vertex_format != draw_list.validation.vertex_format,4921"The vertex format used to create the pipeline does not match the vertex format bound.");4922}49234924if (draw_list.validation.pipeline_push_constant_size > 0) {4925// Using push constants, check that they were supplied.4926ERR_FAIL_COND_MSG(!draw_list.validation.pipeline_push_constant_supplied,4927"The shader in this pipeline requires a push constant to be set before drawing, but it's not present.");4928}4929#endif49304931#ifdef DEBUG_ENABLED4932for (uint32_t i = 0; i < draw_list.state.set_count; i++) {4933if (draw_list.state.sets[i].pipeline_expected_format == 0) {4934// Nothing expected by this pipeline.4935continue;4936}49374938if (draw_list.state.sets[i].pipeline_expected_format != draw_list.state.sets[i].uniform_set_format) {4939if (draw_list.state.sets[i].uniform_set_format == 0) {4940ERR_FAIL_MSG(vformat("Uniforms were never supplied for set (%d) at the time of drawing, which are required by the pipeline.", i));4941} else if (uniform_set_owner.owns(draw_list.state.sets[i].uniform_set)) {4942UniformSet *us = uniform_set_owner.get_or_null(draw_list.state.sets[i].uniform_set);4943ERR_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)));4944} else {4945ERR_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)));4946}4947}4948}4949#endif49504951// Prepare descriptor sets if the API doesn't use pipeline barriers.4952if (!driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) {4953for (uint32_t i = 0; i < draw_list.state.set_count; i++) {4954if (draw_list.state.sets[i].pipeline_expected_format == 0) {4955// Nothing expected by this pipeline.4956continue;4957}49584959draw_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);4960}4961}49624963// Bind descriptor sets.4964for (uint32_t i = 0; i < draw_list.state.set_count; i++) {4965if (draw_list.state.sets[i].pipeline_expected_format == 0) {4966continue; // Nothing expected by this pipeline.4967}4968if (!draw_list.state.sets[i].bound) {4969// All good, see if this requires re-binding.4970draw_graph.add_draw_list_bind_uniform_set(draw_list.state.pipeline_shader_driver_id, draw_list.state.sets[i].uniform_set_driver_id, i);49714972UniformSet *uniform_set = uniform_set_owner.get_or_null(draw_list.state.sets[i].uniform_set);4973_uniform_set_update_shared(uniform_set);49744975draw_graph.add_draw_list_usages(uniform_set->draw_trackers, uniform_set->draw_trackers_usage);49764977draw_list.state.sets[i].bound = true;4978}4979}49804981if (p_use_indices) {4982#ifdef DEBUG_ENABLED4983ERR_FAIL_COND_MSG(!draw_list.validation.index_array_count,4984"Draw command requested indices, but no index buffer was set.");49854986ERR_FAIL_COND_MSG(draw_list.validation.pipeline_uses_restart_indices != draw_list.validation.index_buffer_uses_restart_indices,4987"The usage of restart indices in index buffer does not match the render primitive in the pipeline.");4988#endif49894990ERR_FAIL_COND_MSG(p_offset + 20 > buffer->size, "Offset provided (+20) is past the end of buffer.");49914992draw_graph.add_draw_list_draw_indexed_indirect(buffer->driver_id, p_offset, p_draw_count, p_stride);4993} else {4994ERR_FAIL_COND_MSG(p_offset + 16 > buffer->size, "Offset provided (+16) is past the end of buffer.");49954996draw_graph.add_draw_list_draw_indirect(buffer->driver_id, p_offset, p_draw_count, p_stride);4997}49984999draw_list.state.draw_count++;50005001if (buffer->draw_tracker != nullptr) {5002draw_graph.add_draw_list_usage(buffer->draw_tracker, RDG::RESOURCE_USAGE_INDIRECT_BUFFER_READ);5003}50045005_check_transfer_worker_buffer(buffer);5006}50075008void RenderingDevice::draw_list_set_viewport(DrawListID p_list, const Rect2 &p_rect) {5009ERR_FAIL_COND(!draw_list.active);50105011if (p_rect.get_area() == 0) {5012return;5013}50145015draw_list.viewport = p_rect;5016draw_graph.add_draw_list_set_viewport(p_rect);5017}50185019void RenderingDevice::draw_list_enable_scissor(DrawListID p_list, const Rect2 &p_rect) {5020ERR_RENDER_THREAD_GUARD();50215022ERR_FAIL_COND(!draw_list.active);50235024Rect2i rect = p_rect;5025rect.position += draw_list.viewport.position;50265027rect = draw_list.viewport.intersection(rect);50285029if (rect.get_area() == 0) {5030return;5031}50325033draw_graph.add_draw_list_set_scissor(rect);5034}50355036void RenderingDevice::draw_list_disable_scissor(DrawListID p_list) {5037ERR_RENDER_THREAD_GUARD();50385039ERR_FAIL_COND(!draw_list.active);50405041draw_graph.add_draw_list_set_scissor(draw_list.viewport);5042}50435044uint32_t RenderingDevice::draw_list_get_current_pass() {5045ERR_RENDER_THREAD_GUARD_V(0);50465047return draw_list_current_subpass;5048}50495050RenderingDevice::DrawListID RenderingDevice::draw_list_switch_to_next_pass() {5051ERR_RENDER_THREAD_GUARD_V(INVALID_ID);50525053ERR_FAIL_COND_V(!draw_list.active, INVALID_FORMAT_ID);5054ERR_FAIL_COND_V(draw_list_current_subpass >= draw_list_subpass_count - 1, INVALID_FORMAT_ID);50555056draw_list_current_subpass++;50575058Rect2i viewport;5059_draw_list_end(&viewport);50605061draw_graph.add_draw_list_next_subpass(RDD::COMMAND_BUFFER_TYPE_PRIMARY);50625063_draw_list_start(viewport);50645065return int64_t(ID_TYPE_DRAW_LIST) << ID_BASE_SHIFT;5066}50675068#ifndef DISABLE_DEPRECATED5069Error RenderingDevice::draw_list_switch_to_next_pass_split(uint32_t p_splits, DrawListID *r_split_ids) {5070ERR_FAIL_V_MSG(ERR_UNAVAILABLE, "Deprecated. Split draw lists are used automatically by RenderingDevice.");5071}5072#endif50735074void RenderingDevice::_draw_list_start(const Rect2i &p_viewport) {5075draw_list.viewport = p_viewport;5076draw_list.active = true;5077}50785079void RenderingDevice::_draw_list_end(Rect2i *r_last_viewport) {5080if (r_last_viewport) {5081*r_last_viewport = draw_list.viewport;5082}50835084draw_list = DrawList();5085}50865087void RenderingDevice::draw_list_end() {5088ERR_RENDER_THREAD_GUARD();50895090ERR_FAIL_COND_MSG(!draw_list.active, "Immediate draw list is already inactive.");50915092draw_graph.add_draw_list_end();50935094_draw_list_end();50955096for (uint32_t i = 0; i < draw_list_bound_textures.size(); i++) {5097Texture *texture = texture_owner.get_or_null(draw_list_bound_textures[i]);5098ERR_CONTINUE(!texture); // Wtf.5099if (texture->usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) {5100texture->bound = false;5101}5102if (texture->usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {5103texture->bound = false;5104}5105}51065107draw_list_bound_textures.clear();5108}51095110/***********************/5111/**** COMPUTE LISTS ****/5112/***********************/51135114RenderingDevice::ComputeListID RenderingDevice::compute_list_begin() {5115ERR_RENDER_THREAD_GUARD_V(INVALID_ID);51165117ERR_FAIL_COND_V_MSG(compute_list.active, INVALID_ID, "Only one draw/compute list can be active at the same time.");51185119compute_list.active = true;51205121draw_graph.add_compute_list_begin();51225123return ID_TYPE_COMPUTE_LIST;5124}51255126void RenderingDevice::compute_list_bind_compute_pipeline(ComputeListID p_list, RID p_compute_pipeline) {5127ERR_RENDER_THREAD_GUARD();51285129ERR_FAIL_COND(p_list != ID_TYPE_COMPUTE_LIST);5130ERR_FAIL_COND(!compute_list.active);51315132const ComputePipeline *pipeline = compute_pipeline_owner.get_or_null(p_compute_pipeline);5133ERR_FAIL_NULL(pipeline);51345135if (p_compute_pipeline == compute_list.state.pipeline) {5136return; // Redundant state, return.5137}51385139compute_list.state.pipeline = p_compute_pipeline;51405141draw_graph.add_compute_list_bind_pipeline(pipeline->driver_id);51425143if (compute_list.state.pipeline_shader != pipeline->shader) {5144// Shader changed, so descriptor sets may become incompatible.51455146uint32_t pcount = pipeline->set_formats.size(); // Formats count in this pipeline.5147compute_list.state.set_count = MAX(compute_list.state.set_count, pcount);5148const uint32_t *pformats = pipeline->set_formats.ptr(); // Pipeline set formats.51495150uint32_t first_invalid_set = UINT32_MAX; // All valid by default.5151switch (driver->api_trait_get(RDD::API_TRAIT_SHADER_CHANGE_INVALIDATION)) {5152case RDD::SHADER_CHANGE_INVALIDATION_ALL_BOUND_UNIFORM_SETS: {5153first_invalid_set = 0;5154} break;5155case RDD::SHADER_CHANGE_INVALIDATION_INCOMPATIBLE_SETS_PLUS_CASCADE: {5156for (uint32_t i = 0; i < pcount; i++) {5157if (compute_list.state.sets[i].pipeline_expected_format != pformats[i]) {5158first_invalid_set = i;5159break;5160}5161}5162} break;5163case RDD::SHADER_CHANGE_INVALIDATION_ALL_OR_NONE_ACCORDING_TO_LAYOUT_HASH: {5164if (compute_list.state.pipeline_shader_layout_hash != pipeline->shader_layout_hash) {5165first_invalid_set = 0;5166}5167} break;5168}51695170for (uint32_t i = 0; i < pcount; i++) {5171compute_list.state.sets[i].bound = compute_list.state.sets[i].bound && i < first_invalid_set;5172compute_list.state.sets[i].pipeline_expected_format = pformats[i];5173}51745175for (uint32_t i = pcount; i < compute_list.state.set_count; i++) {5176// Unbind the ones above (not used) if exist.5177compute_list.state.sets[i].bound = false;5178}51795180compute_list.state.set_count = pcount; // Update set count.51815182if (pipeline->push_constant_size) {5183#ifdef DEBUG_ENABLED5184compute_list.validation.pipeline_push_constant_supplied = false;5185#endif5186}51875188compute_list.state.pipeline_shader = pipeline->shader;5189compute_list.state.pipeline_shader_driver_id = pipeline->shader_driver_id;5190compute_list.state.pipeline_shader_layout_hash = pipeline->shader_layout_hash;5191compute_list.state.local_group_size[0] = pipeline->local_group_size[0];5192compute_list.state.local_group_size[1] = pipeline->local_group_size[1];5193compute_list.state.local_group_size[2] = pipeline->local_group_size[2];5194}51955196#ifdef DEBUG_ENABLED5197// Update compute pass pipeline info.5198compute_list.validation.pipeline_active = true;5199compute_list.validation.pipeline_push_constant_size = pipeline->push_constant_size;5200#endif5201}52025203void RenderingDevice::compute_list_bind_uniform_set(ComputeListID p_list, RID p_uniform_set, uint32_t p_index) {5204ERR_RENDER_THREAD_GUARD();52055206ERR_FAIL_COND(p_list != ID_TYPE_COMPUTE_LIST);5207ERR_FAIL_COND(!compute_list.active);52085209#ifdef DEBUG_ENABLED5210ERR_FAIL_COND_MSG(p_index >= driver->limit_get(LIMIT_MAX_BOUND_UNIFORM_SETS) || p_index >= MAX_UNIFORM_SETS,5211"Attempting to bind a descriptor set (" + itos(p_index) + ") greater than what the hardware supports (" + itos(driver->limit_get(LIMIT_MAX_BOUND_UNIFORM_SETS)) + ").");5212#endif52135214UniformSet *uniform_set = uniform_set_owner.get_or_null(p_uniform_set);5215ERR_FAIL_NULL(uniform_set);52165217if (p_index > compute_list.state.set_count) {5218compute_list.state.set_count = p_index;5219}52205221compute_list.state.sets[p_index].uniform_set_driver_id = uniform_set->driver_id; // Update set pointer.5222compute_list.state.sets[p_index].bound = false; // Needs rebind.5223compute_list.state.sets[p_index].uniform_set_format = uniform_set->format;5224compute_list.state.sets[p_index].uniform_set = p_uniform_set;52255226#if 05227{ // Validate that textures bound are not attached as framebuffer bindings.5228uint32_t attachable_count = uniform_set->attachable_textures.size();5229const RID *attachable_ptr = uniform_set->attachable_textures.ptr();5230uint32_t bound_count = draw_list_bound_textures.size();5231const RID *bound_ptr = draw_list_bound_textures.ptr();5232for (uint32_t i = 0; i < attachable_count; i++) {5233for (uint32_t j = 0; j < bound_count; j++) {5234ERR_FAIL_COND_MSG(attachable_ptr[i] == bound_ptr[j],5235"Attempted to use the same texture in framebuffer attachment and a uniform set, this is not allowed.");5236}5237}5238}5239#endif5240}52415242void RenderingDevice::compute_list_set_push_constant(ComputeListID p_list, const void *p_data, uint32_t p_data_size) {5243ERR_RENDER_THREAD_GUARD();52445245ERR_FAIL_COND(p_list != ID_TYPE_COMPUTE_LIST);5246ERR_FAIL_COND(!compute_list.active);5247ERR_FAIL_COND_MSG(p_data_size > MAX_PUSH_CONSTANT_SIZE, "Push constants can't be bigger than 128 bytes to maintain compatibility.");52485249#ifdef DEBUG_ENABLED5250ERR_FAIL_COND_MSG(p_data_size != compute_list.validation.pipeline_push_constant_size,5251"This compute pipeline requires (" + itos(compute_list.validation.pipeline_push_constant_size) + ") bytes of push constant data, supplied: (" + itos(p_data_size) + ")");5252#endif52535254draw_graph.add_compute_list_set_push_constant(compute_list.state.pipeline_shader_driver_id, p_data, p_data_size);52555256// Store it in the state in case we need to restart the compute list.5257memcpy(compute_list.state.push_constant_data, p_data, p_data_size);5258compute_list.state.push_constant_size = p_data_size;52595260#ifdef DEBUG_ENABLED5261compute_list.validation.pipeline_push_constant_supplied = true;5262#endif5263}52645265void RenderingDevice::compute_list_dispatch(ComputeListID p_list, uint32_t p_x_groups, uint32_t p_y_groups, uint32_t p_z_groups) {5266ERR_RENDER_THREAD_GUARD();52675268ERR_FAIL_COND(p_list != ID_TYPE_COMPUTE_LIST);5269ERR_FAIL_COND(!compute_list.active);52705271#ifdef DEBUG_ENABLED5272ERR_FAIL_COND_MSG(p_x_groups == 0, "Dispatch amount of X compute groups (" + itos(p_x_groups) + ") is zero.");5273ERR_FAIL_COND_MSG(p_z_groups == 0, "Dispatch amount of Z compute groups (" + itos(p_z_groups) + ") is zero.");5274ERR_FAIL_COND_MSG(p_y_groups == 0, "Dispatch amount of Y compute groups (" + itos(p_y_groups) + ") is zero.");5275ERR_FAIL_COND_MSG(p_x_groups > driver->limit_get(LIMIT_MAX_COMPUTE_WORKGROUP_COUNT_X),5276"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)) + ")");5277ERR_FAIL_COND_MSG(p_y_groups > driver->limit_get(LIMIT_MAX_COMPUTE_WORKGROUP_COUNT_Y),5278"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)) + ")");5279ERR_FAIL_COND_MSG(p_z_groups > driver->limit_get(LIMIT_MAX_COMPUTE_WORKGROUP_COUNT_Z),5280"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)) + ")");5281#endif52825283#ifdef DEBUG_ENABLED52845285ERR_FAIL_COND_MSG(!compute_list.validation.pipeline_active, "No compute pipeline was set before attempting to draw.");52865287if (compute_list.validation.pipeline_push_constant_size > 0) {5288// Using push constants, check that they were supplied.5289ERR_FAIL_COND_MSG(!compute_list.validation.pipeline_push_constant_supplied,5290"The shader in this pipeline requires a push constant to be set before drawing, but it's not present.");5291}52925293#endif52945295#ifdef DEBUG_ENABLED5296for (uint32_t i = 0; i < compute_list.state.set_count; i++) {5297if (compute_list.state.sets[i].pipeline_expected_format == 0) {5298// Nothing expected by this pipeline.5299continue;5300}53015302if (compute_list.state.sets[i].pipeline_expected_format != compute_list.state.sets[i].uniform_set_format) {5303if (compute_list.state.sets[i].uniform_set_format == 0) {5304ERR_FAIL_MSG("Uniforms were never supplied for set (" + itos(i) + ") at the time of drawing, which are required by the pipeline.");5305} else if (uniform_set_owner.owns(compute_list.state.sets[i].uniform_set)) {5306UniformSet *us = uniform_set_owner.get_or_null(compute_list.state.sets[i].uniform_set);5307ERR_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));5308} else {5309ERR_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));5310}5311}5312}5313#endif5314thread_local LocalVector<RDD::UniformSetID> valid_descriptor_ids;5315valid_descriptor_ids.clear();5316valid_descriptor_ids.resize(compute_list.state.set_count);53175318uint32_t valid_set_count = 0;5319uint32_t first_set_index = 0;5320uint32_t last_set_index = 0;5321bool found_first_set = false;53225323for (uint32_t i = 0; i < compute_list.state.set_count; i++) {5324if (compute_list.state.sets[i].pipeline_expected_format == 0) {5325// Nothing expected by this pipeline.5326continue;5327}53285329if (!compute_list.state.sets[i].bound && !found_first_set) {5330first_set_index = i;5331found_first_set = true;5332}5333// Prepare descriptor sets if the API doesn't use pipeline barriers.5334if (!driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) {5335draw_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);5336}5337}53385339// Bind descriptor sets.5340for (uint32_t i = first_set_index; i < compute_list.state.set_count; i++) {5341if (compute_list.state.sets[i].pipeline_expected_format == 0) {5342continue; // Nothing expected by this pipeline.5343}53445345if (!compute_list.state.sets[i].bound) {5346// Descriptor set batching5347if (descriptor_set_batching) {5348// All good, see if this requires re-binding.5349if (i - last_set_index > 1) {5350// If the descriptor sets are not contiguous, bind the previous ones and start a new batch.5351draw_graph.add_compute_list_bind_uniform_sets(compute_list.state.pipeline_shader_driver_id, valid_descriptor_ids, first_set_index, valid_set_count);53525353first_set_index = i;5354valid_set_count = 1;5355valid_descriptor_ids[0] = compute_list.state.sets[i].uniform_set_driver_id;5356} else {5357// Otherwise, keep storing in the current batch.5358valid_descriptor_ids[valid_set_count] = compute_list.state.sets[i].uniform_set_driver_id;5359valid_set_count++;5360}53615362last_set_index = i;5363} else {5364draw_graph.add_compute_list_bind_uniform_set(compute_list.state.pipeline_shader_driver_id, compute_list.state.sets[i].uniform_set_driver_id, i);5365}5366UniformSet *uniform_set = uniform_set_owner.get_or_null(compute_list.state.sets[i].uniform_set);5367_uniform_set_update_shared(uniform_set);53685369draw_graph.add_compute_list_usages(uniform_set->draw_trackers, uniform_set->draw_trackers_usage);5370compute_list.state.sets[i].bound = true;5371}5372}53735374// Bind the remaining batch.5375if (valid_set_count > 0) {5376draw_graph.add_compute_list_bind_uniform_sets(compute_list.state.pipeline_shader_driver_id, valid_descriptor_ids, first_set_index, valid_set_count);5377}5378draw_graph.add_compute_list_dispatch(p_x_groups, p_y_groups, p_z_groups);5379compute_list.state.dispatch_count++;5380}53815382void RenderingDevice::compute_list_dispatch_threads(ComputeListID p_list, uint32_t p_x_threads, uint32_t p_y_threads, uint32_t p_z_threads) {5383ERR_RENDER_THREAD_GUARD();53845385ERR_FAIL_COND(p_list != ID_TYPE_COMPUTE_LIST);5386ERR_FAIL_COND(!compute_list.active);53875388#ifdef DEBUG_ENABLED5389ERR_FAIL_COND_MSG(p_x_threads == 0, "Dispatch amount of X compute threads (" + itos(p_x_threads) + ") is zero.");5390ERR_FAIL_COND_MSG(p_y_threads == 0, "Dispatch amount of Y compute threads (" + itos(p_y_threads) + ") is zero.");5391ERR_FAIL_COND_MSG(p_z_threads == 0, "Dispatch amount of Z compute threads (" + itos(p_z_threads) + ") is zero.");5392#endif53935394#ifdef DEBUG_ENABLED53955396ERR_FAIL_COND_MSG(!compute_list.validation.pipeline_active, "No compute pipeline was set before attempting to draw.");53975398if (compute_list.validation.pipeline_push_constant_size > 0) {5399// Using push constants, check that they were supplied.5400ERR_FAIL_COND_MSG(!compute_list.validation.pipeline_push_constant_supplied,5401"The shader in this pipeline requires a push constant to be set before drawing, but it's not present.");5402}54035404#endif54055406compute_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]));5407}54085409void RenderingDevice::compute_list_dispatch_indirect(ComputeListID p_list, RID p_buffer, uint32_t p_offset) {5410ERR_RENDER_THREAD_GUARD();54115412ERR_FAIL_COND(p_list != ID_TYPE_COMPUTE_LIST);5413ERR_FAIL_COND(!compute_list.active);54145415Buffer *buffer = storage_buffer_owner.get_or_null(p_buffer);5416ERR_FAIL_NULL(buffer);54175418ERR_FAIL_COND_MSG(!buffer->usage.has_flag(RDD::BUFFER_USAGE_INDIRECT_BIT), "Buffer provided was not created to do indirect dispatch.");54195420ERR_FAIL_COND_MSG(p_offset + 12 > buffer->size, "Offset provided (+12) is past the end of buffer.");54215422#ifdef DEBUG_ENABLED54235424ERR_FAIL_COND_MSG(!compute_list.validation.pipeline_active, "No compute pipeline was set before attempting to draw.");54255426if (compute_list.validation.pipeline_push_constant_size > 0) {5427// Using push constants, check that they were supplied.5428ERR_FAIL_COND_MSG(!compute_list.validation.pipeline_push_constant_supplied,5429"The shader in this pipeline requires a push constant to be set before drawing, but it's not present.");5430}54315432#endif54335434#ifdef DEBUG_ENABLED5435for (uint32_t i = 0; i < compute_list.state.set_count; i++) {5436if (compute_list.state.sets[i].pipeline_expected_format == 0) {5437// Nothing expected by this pipeline.5438continue;5439}54405441if (compute_list.state.sets[i].pipeline_expected_format != compute_list.state.sets[i].uniform_set_format) {5442if (compute_list.state.sets[i].uniform_set_format == 0) {5443ERR_FAIL_MSG("Uniforms were never supplied for set (" + itos(i) + ") at the time of drawing, which are required by the pipeline.");5444} else if (uniform_set_owner.owns(compute_list.state.sets[i].uniform_set)) {5445UniformSet *us = uniform_set_owner.get_or_null(compute_list.state.sets[i].uniform_set);5446ERR_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));5447} else {5448ERR_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));5449}5450}5451}5452#endif5453thread_local LocalVector<RDD::UniformSetID> valid_descriptor_ids;5454valid_descriptor_ids.clear();5455valid_descriptor_ids.resize(compute_list.state.set_count);54565457uint32_t valid_set_count = 0;5458uint32_t first_set_index = 0;5459uint32_t last_set_index = 0;5460bool found_first_set = false;54615462for (uint32_t i = 0; i < compute_list.state.set_count; i++) {5463if (compute_list.state.sets[i].pipeline_expected_format == 0) {5464// Nothing expected by this pipeline.5465continue;5466}54675468if (!compute_list.state.sets[i].bound && !found_first_set) {5469first_set_index = i;5470found_first_set = true;5471}54725473// Prepare descriptor sets if the API doesn't use pipeline barriers.5474if (!driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) {5475draw_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);5476}5477}54785479// Bind descriptor sets.5480for (uint32_t i = first_set_index; i < compute_list.state.set_count; i++) {5481if (compute_list.state.sets[i].pipeline_expected_format == 0) {5482continue; // Nothing expected by this pipeline.5483}54845485if (!compute_list.state.sets[i].bound) {5486// All good, see if this requires re-binding.5487if (i - last_set_index > 1) {5488// If the descriptor sets are not contiguous, bind the previous ones and start a new batch.5489draw_graph.add_compute_list_bind_uniform_sets(compute_list.state.pipeline_shader_driver_id, valid_descriptor_ids, first_set_index, valid_set_count);54905491first_set_index = i;5492valid_set_count = 1;5493valid_descriptor_ids[0] = compute_list.state.sets[i].uniform_set_driver_id;5494} else {5495// Otherwise, keep storing in the current batch.5496valid_descriptor_ids[valid_set_count] = compute_list.state.sets[i].uniform_set_driver_id;5497valid_set_count++;5498}54995500last_set_index = i;55015502UniformSet *uniform_set = uniform_set_owner.get_or_null(compute_list.state.sets[i].uniform_set);5503_uniform_set_update_shared(uniform_set);55045505draw_graph.add_compute_list_usages(uniform_set->draw_trackers, uniform_set->draw_trackers_usage);5506compute_list.state.sets[i].bound = true;5507}5508}55095510// Bind the remaining batch.5511if (valid_set_count > 0) {5512draw_graph.add_compute_list_bind_uniform_sets(compute_list.state.pipeline_shader_driver_id, valid_descriptor_ids, first_set_index, valid_set_count);5513}55145515draw_graph.add_compute_list_dispatch_indirect(buffer->driver_id, p_offset);5516compute_list.state.dispatch_count++;55175518if (buffer->draw_tracker != nullptr) {5519draw_graph.add_compute_list_usage(buffer->draw_tracker, RDG::RESOURCE_USAGE_INDIRECT_BUFFER_READ);5520}55215522_check_transfer_worker_buffer(buffer);5523}55245525void RenderingDevice::compute_list_add_barrier(ComputeListID p_list) {5526ERR_RENDER_THREAD_GUARD();55275528compute_list_barrier_state = compute_list.state;5529compute_list_end();5530compute_list_begin();55315532if (compute_list_barrier_state.pipeline.is_valid()) {5533compute_list_bind_compute_pipeline(p_list, compute_list_barrier_state.pipeline);5534}55355536for (uint32_t i = 0; i < compute_list_barrier_state.set_count; i++) {5537if (compute_list_barrier_state.sets[i].uniform_set.is_valid()) {5538compute_list_bind_uniform_set(p_list, compute_list_barrier_state.sets[i].uniform_set, i);5539}5540}55415542if (compute_list_barrier_state.push_constant_size > 0) {5543compute_list_set_push_constant(p_list, compute_list_barrier_state.push_constant_data, compute_list_barrier_state.push_constant_size);5544}5545}55465547void RenderingDevice::compute_list_end() {5548ERR_RENDER_THREAD_GUARD();55495550ERR_FAIL_COND(!compute_list.active);55515552draw_graph.add_compute_list_end();55535554compute_list = ComputeList();5555}55565557#ifndef DISABLE_DEPRECATED5558void RenderingDevice::barrier(BitField<BarrierMask> p_from, BitField<BarrierMask> p_to) {5559WARN_PRINT("Deprecated. Barriers are automatically inserted by RenderingDevice.");5560}55615562void RenderingDevice::full_barrier() {5563WARN_PRINT("Deprecated. Barriers are automatically inserted by RenderingDevice.");5564}5565#endif55665567/*************************/5568/**** TRANSFER WORKER ****/5569/*************************/55705571static uint32_t _get_alignment_offset(uint32_t p_offset, uint32_t p_required_align) {5572uint32_t alignment_offset = (p_required_align > 0) ? (p_offset % p_required_align) : 0;5573if (alignment_offset != 0) {5574// If a particular alignment is required, add the offset as part of the required size.5575alignment_offset = p_required_align - alignment_offset;5576}55775578return alignment_offset;5579}55805581RenderingDevice::TransferWorker *RenderingDevice::_acquire_transfer_worker(uint32_t p_transfer_size, uint32_t p_required_align, uint32_t &r_staging_offset) {5582// Find the first worker that is not currently executing anything and has enough size for the transfer.5583// 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.5584TransferWorker *transfer_worker = nullptr;5585uint32_t available_list_index = 0;5586bool transfer_worker_busy = true;5587bool transfer_worker_full = true;5588{5589MutexLock pool_lock(transfer_worker_pool_mutex);55905591// If no workers are available and we've reached the max pool capacity, wait until one of them becomes available.5592bool transfer_worker_pool_full = transfer_worker_pool.size() >= transfer_worker_pool_max_size;5593while (transfer_worker_pool_available_list.is_empty() && transfer_worker_pool_full) {5594transfer_worker_pool_condition.wait(pool_lock);5595}55965597// Look at all available workers first.5598for (uint32_t i = 0; i < transfer_worker_pool_available_list.size(); i++) {5599uint32_t worker_index = transfer_worker_pool_available_list[i];5600TransferWorker *candidate_worker = transfer_worker_pool[worker_index];5601candidate_worker->thread_mutex.lock();56025603// Figure out if the worker can fit the transfer.5604uint32_t alignment_offset = _get_alignment_offset(candidate_worker->staging_buffer_size_in_use, p_required_align);5605uint32_t required_size = candidate_worker->staging_buffer_size_in_use + p_transfer_size + alignment_offset;5606bool candidate_worker_busy = candidate_worker->submitted;5607bool candidate_worker_full = required_size > candidate_worker->staging_buffer_size_allocated;5608bool pick_candidate = false;5609if (!candidate_worker_busy && !candidate_worker_full) {5610// A worker that can fit the transfer and is not waiting for a previous execution is the best possible candidate.5611pick_candidate = true;5612} else if (!candidate_worker_busy) {5613// The worker can't fit the transfer but it's not currently doing anything.5614// We pick it as a possible candidate if the current one is busy.5615pick_candidate = transfer_worker_busy;5616} else if (!candidate_worker_full) {5617// The worker can fit the transfer but it's currently executing previous work.5618// We pick it as a possible candidate if the current one is both busy and full.5619pick_candidate = transfer_worker_busy && transfer_worker_full;5620} else if (transfer_worker == nullptr) {5621// The worker can't fit the transfer and it's currently executing work, so it's the worst candidate.5622// We only pick if no candidate has been picked yet.5623pick_candidate = true;5624}56255626if (pick_candidate) {5627if (transfer_worker != nullptr) {5628// Release the lock for the worker that was picked previously.5629transfer_worker->thread_mutex.unlock();5630}56315632// Keep the lock active for this worker.5633transfer_worker = candidate_worker;5634transfer_worker_busy = candidate_worker_busy;5635transfer_worker_full = candidate_worker_full;5636available_list_index = i;56375638if (!transfer_worker_busy && !transfer_worker_full) {5639// Best possible candidate, stop searching early.5640break;5641}5642} else {5643// Release the lock for the candidate.5644candidate_worker->thread_mutex.unlock();5645}5646}56475648if (transfer_worker != nullptr) {5649// A worker was picked, remove it from the available list.5650transfer_worker_pool_available_list.remove_at(available_list_index);5651} else {5652DEV_ASSERT(!transfer_worker_pool_full && "A transfer worker should never be created when the pool is full.");56535654// No existing worker was picked, we create a new one.5655transfer_worker = memnew(TransferWorker);5656transfer_worker->command_fence = driver->fence_create();5657transfer_worker->command_pool = driver->command_pool_create(transfer_queue_family, RDD::COMMAND_BUFFER_TYPE_PRIMARY);5658transfer_worker->command_buffer = driver->command_buffer_create(transfer_worker->command_pool);5659transfer_worker->index = transfer_worker_pool.size();5660transfer_worker_pool.push_back(transfer_worker);5661transfer_worker_operation_used_by_draw.push_back(0);5662transfer_worker->thread_mutex.lock();5663}5664}56655666if (transfer_worker->submitted) {5667// Wait for the worker if the command buffer was submitted but it hasn't finished processing yet.5668_wait_for_transfer_worker(transfer_worker);5669}56705671uint32_t alignment_offset = _get_alignment_offset(transfer_worker->staging_buffer_size_in_use, p_required_align);5672transfer_worker->max_transfer_size = MAX(transfer_worker->max_transfer_size, p_transfer_size);56735674uint32_t required_size = transfer_worker->staging_buffer_size_in_use + p_transfer_size + alignment_offset;5675if (required_size > transfer_worker->staging_buffer_size_allocated) {5676// 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.5677if (transfer_worker->recording) {5678_end_transfer_worker(transfer_worker);5679_submit_transfer_worker(transfer_worker);5680}56815682if (transfer_worker->submitted) {5683_wait_for_transfer_worker(transfer_worker);5684}56855686alignment_offset = 0;56875688// If the staging buffer can't fit the transfer, we recreate the buffer.5689const uint32_t expected_buffer_size_minimum = 16 * 1024;5690uint32_t expected_buffer_size = MAX(transfer_worker->max_transfer_size, expected_buffer_size_minimum);5691if (expected_buffer_size > transfer_worker->staging_buffer_size_allocated) {5692if (transfer_worker->staging_buffer.id != 0) {5693driver->buffer_free(transfer_worker->staging_buffer);5694}56955696uint32_t new_staging_buffer_size = next_power_of_2(expected_buffer_size);5697transfer_worker->staging_buffer_size_allocated = new_staging_buffer_size;5698transfer_worker->staging_buffer = driver->buffer_create(new_staging_buffer_size, RDD::BUFFER_USAGE_TRANSFER_FROM_BIT, RDD::MEMORY_ALLOCATION_TYPE_CPU);5699}5700}57015702// Add the alignment before storing the offset that will be returned.5703transfer_worker->staging_buffer_size_in_use += alignment_offset;57045705// Store the offset to return and increment the current size.5706r_staging_offset = transfer_worker->staging_buffer_size_in_use;5707transfer_worker->staging_buffer_size_in_use += p_transfer_size;57085709if (!transfer_worker->recording) {5710// Begin the command buffer if the worker wasn't recording yet.5711driver->command_buffer_begin(transfer_worker->command_buffer);5712transfer_worker->recording = true;5713}57145715return transfer_worker;5716}57175718void RenderingDevice::_release_transfer_worker(TransferWorker *p_transfer_worker) {5719p_transfer_worker->thread_mutex.unlock();57205721transfer_worker_pool_mutex.lock();5722transfer_worker_pool_available_list.push_back(p_transfer_worker->index);5723transfer_worker_pool_mutex.unlock();5724transfer_worker_pool_condition.notify_one();5725}57265727void RenderingDevice::_end_transfer_worker(TransferWorker *p_transfer_worker) {5728driver->command_buffer_end(p_transfer_worker->command_buffer);5729p_transfer_worker->recording = false;5730}57315732void RenderingDevice::_submit_transfer_worker(TransferWorker *p_transfer_worker, VectorView<RDD::SemaphoreID> p_signal_semaphores) {5733driver->command_queue_execute_and_present(transfer_queue, {}, p_transfer_worker->command_buffer, p_signal_semaphores, p_transfer_worker->command_fence, {});57345735for (uint32_t i = 0; i < p_signal_semaphores.size(); i++) {5736// Indicate the frame should wait on these semaphores before executing the main command buffer.5737frames[frame].semaphores_to_wait_on.push_back(p_signal_semaphores[i]);5738}57395740p_transfer_worker->submitted = true;57415742{5743MutexLock lock(p_transfer_worker->operations_mutex);5744p_transfer_worker->operations_submitted = p_transfer_worker->operations_counter;5745}5746}57475748void RenderingDevice::_wait_for_transfer_worker(TransferWorker *p_transfer_worker) {5749driver->fence_wait(p_transfer_worker->command_fence);5750driver->command_pool_reset(p_transfer_worker->command_pool);5751p_transfer_worker->staging_buffer_size_in_use = 0;5752p_transfer_worker->submitted = false;57535754{5755MutexLock lock(p_transfer_worker->operations_mutex);5756p_transfer_worker->operations_processed = p_transfer_worker->operations_submitted;5757}57585759_flush_barriers_for_transfer_worker(p_transfer_worker);5760}57615762void RenderingDevice::_flush_barriers_for_transfer_worker(TransferWorker *p_transfer_worker) {5763// Caller must have already acquired the mutex for the worker.5764if (!p_transfer_worker->texture_barriers.is_empty()) {5765MutexLock transfer_worker_lock(transfer_worker_pool_texture_barriers_mutex);5766for (uint32_t i = 0; i < p_transfer_worker->texture_barriers.size(); i++) {5767transfer_worker_pool_texture_barriers.push_back(p_transfer_worker->texture_barriers[i]);5768}57695770p_transfer_worker->texture_barriers.clear();5771}5772}57735774void RenderingDevice::_check_transfer_worker_operation(uint32_t p_transfer_worker_index, uint64_t p_transfer_worker_operation) {5775TransferWorker *transfer_worker = transfer_worker_pool[p_transfer_worker_index];5776MutexLock lock(transfer_worker->operations_mutex);5777uint64_t &dst_operation = transfer_worker_operation_used_by_draw[transfer_worker->index];5778dst_operation = MAX(dst_operation, p_transfer_worker_operation);5779}57805781void RenderingDevice::_check_transfer_worker_buffer(Buffer *p_buffer) {5782if (p_buffer->transfer_worker_index >= 0) {5783_check_transfer_worker_operation(p_buffer->transfer_worker_index, p_buffer->transfer_worker_operation);5784p_buffer->transfer_worker_index = -1;5785}5786}57875788void RenderingDevice::_check_transfer_worker_texture(Texture *p_texture) {5789if (p_texture->transfer_worker_index >= 0) {5790_check_transfer_worker_operation(p_texture->transfer_worker_index, p_texture->transfer_worker_operation);5791p_texture->transfer_worker_index = -1;5792}5793}57945795void RenderingDevice::_check_transfer_worker_vertex_array(VertexArray *p_vertex_array) {5796if (!p_vertex_array->transfer_worker_indices.is_empty()) {5797for (int i = 0; i < p_vertex_array->transfer_worker_indices.size(); i++) {5798_check_transfer_worker_operation(p_vertex_array->transfer_worker_indices[i], p_vertex_array->transfer_worker_operations[i]);5799}58005801p_vertex_array->transfer_worker_indices.clear();5802p_vertex_array->transfer_worker_operations.clear();5803}5804}58055806void RenderingDevice::_check_transfer_worker_index_array(IndexArray *p_index_array) {5807if (p_index_array->transfer_worker_index >= 0) {5808_check_transfer_worker_operation(p_index_array->transfer_worker_index, p_index_array->transfer_worker_operation);5809p_index_array->transfer_worker_index = -1;5810}5811}58125813void RenderingDevice::_submit_transfer_workers(RDD::CommandBufferID p_draw_command_buffer) {5814MutexLock transfer_worker_lock(transfer_worker_pool_mutex);5815for (uint32_t i = 0; i < transfer_worker_pool.size(); i++) {5816TransferWorker *worker = transfer_worker_pool[i];5817if (p_draw_command_buffer) {5818MutexLock lock(worker->operations_mutex);5819if (worker->operations_processed >= transfer_worker_operation_used_by_draw[worker->index]) {5820// The operation used by the draw has already been processed, we don't need to wait on the worker.5821continue;5822}5823}58245825{5826MutexLock lock(worker->thread_mutex);5827if (worker->recording) {5828VectorView<RDD::SemaphoreID> semaphores = p_draw_command_buffer ? frames[frame].transfer_worker_semaphores[i] : VectorView<RDD::SemaphoreID>();5829_end_transfer_worker(worker);5830_submit_transfer_worker(worker, semaphores);5831}58325833if (p_draw_command_buffer) {5834_flush_barriers_for_transfer_worker(worker);5835}5836}5837}5838}58395840void RenderingDevice::_submit_transfer_barriers(RDD::CommandBufferID p_draw_command_buffer) {5841MutexLock transfer_worker_lock(transfer_worker_pool_texture_barriers_mutex);5842if (!transfer_worker_pool_texture_barriers.is_empty()) {5843driver->command_pipeline_barrier(p_draw_command_buffer, RDD::PIPELINE_STAGE_COPY_BIT, RDD::PIPELINE_STAGE_ALL_COMMANDS_BIT, {}, {}, transfer_worker_pool_texture_barriers);5844transfer_worker_pool_texture_barriers.clear();5845}5846}58475848void RenderingDevice::_wait_for_transfer_workers() {5849MutexLock transfer_worker_lock(transfer_worker_pool_mutex);5850for (TransferWorker *worker : transfer_worker_pool) {5851MutexLock lock(worker->thread_mutex);5852if (worker->submitted) {5853_wait_for_transfer_worker(worker);5854}5855}5856}58575858void RenderingDevice::_free_transfer_workers() {5859MutexLock transfer_worker_lock(transfer_worker_pool_mutex);5860for (TransferWorker *worker : transfer_worker_pool) {5861driver->fence_free(worker->command_fence);5862driver->buffer_free(worker->staging_buffer);5863driver->command_pool_free(worker->command_pool);5864memdelete(worker);5865}58665867transfer_worker_pool.clear();5868}58695870/***********************/5871/**** COMMAND GRAPH ****/5872/***********************/58735874bool RenderingDevice::_texture_make_mutable(Texture *p_texture, RID p_texture_id) {5875if (p_texture->draw_tracker != nullptr) {5876// Texture already has a tracker.5877return false;5878} else {5879if (p_texture->owner.is_valid()) {5880// Texture has an owner.5881Texture *owner_texture = texture_owner.get_or_null(p_texture->owner);5882ERR_FAIL_NULL_V(owner_texture, false);58835884if (owner_texture->draw_tracker != nullptr) {5885// Create a tracker for this dependency in particular.5886if (p_texture->slice_type == TEXTURE_SLICE_MAX) {5887// Shared texture.5888p_texture->draw_tracker = owner_texture->draw_tracker;5889p_texture->draw_tracker->reference_count++;5890} else {5891// Slice texture.5892if (owner_texture->slice_trackers == nullptr) {5893owner_texture->slice_trackers = memnew((HashMap<Rect2i, RDG::ResourceTracker *>));5894}5895HashMap<Rect2i, RDG::ResourceTracker *>::ConstIterator draw_tracker_iterator = owner_texture->slice_trackers->find(p_texture->slice_rect);5896RDG::ResourceTracker *draw_tracker = nullptr;5897if (draw_tracker_iterator != owner_texture->slice_trackers->end()) {5898// Reuse the tracker at the matching rectangle.5899draw_tracker = draw_tracker_iterator->value;5900} else {5901// Create a new tracker and store it on the map.5902draw_tracker = RDG::resource_tracker_create();5903draw_tracker->parent = owner_texture->draw_tracker;5904draw_tracker->texture_driver_id = p_texture->driver_id;5905draw_tracker->texture_size = Size2i(p_texture->width, p_texture->height);5906draw_tracker->texture_subresources = p_texture->barrier_range();5907draw_tracker->texture_usage = p_texture->usage_flags;5908draw_tracker->texture_slice_or_dirty_rect = p_texture->slice_rect;5909(*owner_texture->slice_trackers)[p_texture->slice_rect] = draw_tracker;5910}59115912p_texture->draw_tracker = draw_tracker;5913p_texture->draw_tracker->reference_count++;5914}59155916if (p_texture_id.is_valid()) {5917_dependencies_make_mutable(p_texture_id, p_texture->draw_tracker);5918}5919} else {5920// Delegate this to the owner instead, as it'll make all its dependencies mutable.5921_texture_make_mutable(owner_texture, p_texture->owner);5922}5923} else {5924// Regular texture.5925p_texture->draw_tracker = RDG::resource_tracker_create();5926p_texture->draw_tracker->texture_driver_id = p_texture->driver_id;5927p_texture->draw_tracker->texture_size = Size2i(p_texture->width, p_texture->height);5928p_texture->draw_tracker->texture_subresources = p_texture->barrier_range();5929p_texture->draw_tracker->texture_usage = p_texture->usage_flags;5930p_texture->draw_tracker->is_discardable = p_texture->is_discardable;5931p_texture->draw_tracker->reference_count = 1;59325933if (p_texture_id.is_valid()) {5934if (p_texture->has_initial_data) {5935// If the texture was initialized with initial data but wasn't made mutable from the start, assume the texture sampling usage.5936p_texture->draw_tracker->usage = RDG::RESOURCE_USAGE_TEXTURE_SAMPLE;5937}59385939_dependencies_make_mutable(p_texture_id, p_texture->draw_tracker);5940}5941}59425943return true;5944}5945}59465947bool RenderingDevice::_buffer_make_mutable(Buffer *p_buffer, RID p_buffer_id) {5948if (p_buffer->draw_tracker != nullptr) {5949// Buffer already has a tracker.5950return false;5951} else {5952// Create a tracker for the buffer and make all its dependencies mutable.5953p_buffer->draw_tracker = RDG::resource_tracker_create();5954p_buffer->draw_tracker->buffer_driver_id = p_buffer->driver_id;5955if (p_buffer_id.is_valid()) {5956_dependencies_make_mutable(p_buffer_id, p_buffer->draw_tracker);5957}59585959return true;5960}5961}59625963bool RenderingDevice::_vertex_array_make_mutable(VertexArray *p_vertex_array, RID p_resource_id, RDG::ResourceTracker *p_resource_tracker) {5964if (!p_vertex_array->untracked_buffers.has(p_resource_id)) {5965// Vertex array thinks the buffer is already tracked or does not use it.5966return false;5967} else {5968// Vertex array is aware of the buffer but it isn't being tracked.5969p_vertex_array->draw_trackers.push_back(p_resource_tracker);5970p_vertex_array->untracked_buffers.erase(p_resource_id);5971return true;5972}5973}59745975bool RenderingDevice::_index_array_make_mutable(IndexArray *p_index_array, RDG::ResourceTracker *p_resource_tracker) {5976if (p_index_array->draw_tracker != nullptr) {5977// Index array already has a tracker.5978return false;5979} else {5980// Index array should assign the tracker from the buffer.5981p_index_array->draw_tracker = p_resource_tracker;5982return true;5983}5984}59855986bool RenderingDevice::_uniform_set_make_mutable(UniformSet *p_uniform_set, RID p_resource_id, RDG::ResourceTracker *p_resource_tracker) {5987HashMap<RID, RDG::ResourceUsage>::Iterator E = p_uniform_set->untracked_usage.find(p_resource_id);5988if (!E) {5989// Uniform set thinks the resource is already tracked or does not use it.5990return false;5991} else {5992// Uniform set has seen the resource but hasn't added its tracker yet.5993p_uniform_set->draw_trackers.push_back(p_resource_tracker);5994p_uniform_set->draw_trackers_usage.push_back(E->value);5995p_uniform_set->untracked_usage.remove(E);5996return true;5997}5998}59996000bool RenderingDevice::_dependency_make_mutable(RID p_id, RID p_resource_id, RDG::ResourceTracker *p_resource_tracker) {6001if (texture_owner.owns(p_id)) {6002Texture *texture = texture_owner.get_or_null(p_id);6003return _texture_make_mutable(texture, p_id);6004} else if (vertex_array_owner.owns(p_id)) {6005VertexArray *vertex_array = vertex_array_owner.get_or_null(p_id);6006return _vertex_array_make_mutable(vertex_array, p_resource_id, p_resource_tracker);6007} else if (index_array_owner.owns(p_id)) {6008IndexArray *index_array = index_array_owner.get_or_null(p_id);6009return _index_array_make_mutable(index_array, p_resource_tracker);6010} else if (uniform_set_owner.owns(p_id)) {6011UniformSet *uniform_set = uniform_set_owner.get_or_null(p_id);6012return _uniform_set_make_mutable(uniform_set, p_resource_id, p_resource_tracker);6013} else {6014DEV_ASSERT(false && "Unknown resource type to make mutable.");6015return false;6016}6017}60186019bool RenderingDevice::_dependencies_make_mutable_recursive(RID p_id, RDG::ResourceTracker *p_resource_tracker) {6020bool made_mutable = false;6021HashMap<RID, HashSet<RID>>::Iterator E = dependency_map.find(p_id);6022if (E) {6023for (RID rid : E->value) {6024made_mutable = _dependency_make_mutable(rid, p_id, p_resource_tracker) || made_mutable;6025}6026}60276028return made_mutable;6029}60306031bool RenderingDevice::_dependencies_make_mutable(RID p_id, RDG::ResourceTracker *p_resource_tracker) {6032_THREAD_SAFE_METHOD_6033return _dependencies_make_mutable_recursive(p_id, p_resource_tracker);6034}60356036/**************************/6037/**** FRAME MANAGEMENT ****/6038/**************************/60396040void RenderingDevice::free_rid(RID p_rid) {6041ERR_RENDER_THREAD_GUARD();60426043_free_dependencies(p_rid); // Recursively erase dependencies first, to avoid potential API problems.6044_free_internal(p_rid);6045}60466047void RenderingDevice::_free_internal(RID p_id) {6048#ifdef DEV_ENABLED6049String resource_name;6050if (resource_names.has(p_id)) {6051resource_name = resource_names[p_id];6052resource_names.erase(p_id);6053}6054#endif60556056// Push everything so it's disposed of next time this frame index is processed (means, it's safe to do it).6057if (texture_owner.owns(p_id)) {6058Texture *texture = texture_owner.get_or_null(p_id);6059_check_transfer_worker_texture(texture);60606061RDG::ResourceTracker *draw_tracker = texture->draw_tracker;6062if (draw_tracker != nullptr) {6063draw_tracker->reference_count--;6064if (draw_tracker->reference_count == 0) {6065RDG::resource_tracker_free(draw_tracker);60666067if (texture->owner.is_valid() && (texture->slice_type != TEXTURE_SLICE_MAX)) {6068// If this was a texture slice, erase the tracker from the map.6069Texture *owner_texture = texture_owner.get_or_null(texture->owner);6070if (owner_texture != nullptr && owner_texture->slice_trackers != nullptr) {6071owner_texture->slice_trackers->erase(texture->slice_rect);60726073if (owner_texture->slice_trackers->is_empty()) {6074memdelete(owner_texture->slice_trackers);6075owner_texture->slice_trackers = nullptr;6076}6077}6078}6079}6080}60816082frames[frame].textures_to_dispose_of.push_back(*texture);6083texture_owner.free(p_id);6084} else if (framebuffer_owner.owns(p_id)) {6085Framebuffer *framebuffer = framebuffer_owner.get_or_null(p_id);6086frames[frame].framebuffers_to_dispose_of.push_back(*framebuffer);60876088if (framebuffer->invalidated_callback != nullptr) {6089framebuffer->invalidated_callback(framebuffer->invalidated_callback_userdata);6090}60916092framebuffer_owner.free(p_id);6093} else if (sampler_owner.owns(p_id)) {6094RDD::SamplerID sampler_driver_id = *sampler_owner.get_or_null(p_id);6095frames[frame].samplers_to_dispose_of.push_back(sampler_driver_id);6096sampler_owner.free(p_id);6097} else if (vertex_buffer_owner.owns(p_id)) {6098Buffer *vertex_buffer = vertex_buffer_owner.get_or_null(p_id);6099_check_transfer_worker_buffer(vertex_buffer);61006101RDG::resource_tracker_free(vertex_buffer->draw_tracker);6102frames[frame].buffers_to_dispose_of.push_back(*vertex_buffer);6103vertex_buffer_owner.free(p_id);6104} else if (vertex_array_owner.owns(p_id)) {6105vertex_array_owner.free(p_id);6106} else if (index_buffer_owner.owns(p_id)) {6107IndexBuffer *index_buffer = index_buffer_owner.get_or_null(p_id);6108_check_transfer_worker_buffer(index_buffer);61096110RDG::resource_tracker_free(index_buffer->draw_tracker);6111frames[frame].buffers_to_dispose_of.push_back(*index_buffer);6112index_buffer_owner.free(p_id);6113} else if (index_array_owner.owns(p_id)) {6114index_array_owner.free(p_id);6115} else if (shader_owner.owns(p_id)) {6116Shader *shader = shader_owner.get_or_null(p_id);6117if (shader->driver_id) { // Not placeholder?6118frames[frame].shaders_to_dispose_of.push_back(*shader);6119}6120shader_owner.free(p_id);6121} else if (uniform_buffer_owner.owns(p_id)) {6122Buffer *uniform_buffer = uniform_buffer_owner.get_or_null(p_id);6123_check_transfer_worker_buffer(uniform_buffer);61246125RDG::resource_tracker_free(uniform_buffer->draw_tracker);6126frames[frame].buffers_to_dispose_of.push_back(*uniform_buffer);6127uniform_buffer_owner.free(p_id);6128} else if (texture_buffer_owner.owns(p_id)) {6129Buffer *texture_buffer = texture_buffer_owner.get_or_null(p_id);6130_check_transfer_worker_buffer(texture_buffer);61316132RDG::resource_tracker_free(texture_buffer->draw_tracker);6133frames[frame].buffers_to_dispose_of.push_back(*texture_buffer);6134texture_buffer_owner.free(p_id);6135} else if (storage_buffer_owner.owns(p_id)) {6136Buffer *storage_buffer = storage_buffer_owner.get_or_null(p_id);6137_check_transfer_worker_buffer(storage_buffer);61386139RDG::resource_tracker_free(storage_buffer->draw_tracker);6140frames[frame].buffers_to_dispose_of.push_back(*storage_buffer);6141storage_buffer_owner.free(p_id);6142} else if (uniform_set_owner.owns(p_id)) {6143UniformSet *uniform_set = uniform_set_owner.get_or_null(p_id);6144frames[frame].uniform_sets_to_dispose_of.push_back(*uniform_set);6145uniform_set_owner.free(p_id);61466147if (uniform_set->invalidated_callback != nullptr) {6148uniform_set->invalidated_callback(uniform_set->invalidated_callback_userdata);6149}6150} else if (render_pipeline_owner.owns(p_id)) {6151RenderPipeline *pipeline = render_pipeline_owner.get_or_null(p_id);6152frames[frame].render_pipelines_to_dispose_of.push_back(*pipeline);6153render_pipeline_owner.free(p_id);6154} else if (compute_pipeline_owner.owns(p_id)) {6155ComputePipeline *pipeline = compute_pipeline_owner.get_or_null(p_id);6156frames[frame].compute_pipelines_to_dispose_of.push_back(*pipeline);6157compute_pipeline_owner.free(p_id);6158} else {6159#ifdef DEV_ENABLED6160ERR_PRINT("Attempted to free invalid ID: " + itos(p_id.get_id()) + " " + resource_name);6161#else6162ERR_PRINT("Attempted to free invalid ID: " + itos(p_id.get_id()));6163#endif6164}61656166frames_pending_resources_for_processing = uint32_t(frames.size());6167}61686169// The full list of resources that can be named is in the VkObjectType enum.6170// We just expose the resources that are owned and can be accessed easily.6171void RenderingDevice::set_resource_name(RID p_id, const String &p_name) {6172_THREAD_SAFE_METHOD_61736174if (texture_owner.owns(p_id)) {6175Texture *texture = texture_owner.get_or_null(p_id);6176driver->set_object_name(RDD::OBJECT_TYPE_TEXTURE, texture->driver_id, p_name);6177} else if (framebuffer_owner.owns(p_id)) {6178//Framebuffer *framebuffer = framebuffer_owner.get_or_null(p_id);6179// Not implemented for now as the relationship between Framebuffer and RenderPass is very complex.6180} else if (sampler_owner.owns(p_id)) {6181RDD::SamplerID sampler_driver_id = *sampler_owner.get_or_null(p_id);6182driver->set_object_name(RDD::OBJECT_TYPE_SAMPLER, sampler_driver_id, p_name);6183} else if (vertex_buffer_owner.owns(p_id)) {6184Buffer *vertex_buffer = vertex_buffer_owner.get_or_null(p_id);6185driver->set_object_name(RDD::OBJECT_TYPE_BUFFER, vertex_buffer->driver_id, p_name);6186} else if (index_buffer_owner.owns(p_id)) {6187IndexBuffer *index_buffer = index_buffer_owner.get_or_null(p_id);6188driver->set_object_name(RDD::OBJECT_TYPE_BUFFER, index_buffer->driver_id, p_name);6189} else if (shader_owner.owns(p_id)) {6190Shader *shader = shader_owner.get_or_null(p_id);6191driver->set_object_name(RDD::OBJECT_TYPE_SHADER, shader->driver_id, p_name);6192} else if (uniform_buffer_owner.owns(p_id)) {6193Buffer *uniform_buffer = uniform_buffer_owner.get_or_null(p_id);6194driver->set_object_name(RDD::OBJECT_TYPE_BUFFER, uniform_buffer->driver_id, p_name);6195} else if (texture_buffer_owner.owns(p_id)) {6196Buffer *texture_buffer = texture_buffer_owner.get_or_null(p_id);6197driver->set_object_name(RDD::OBJECT_TYPE_BUFFER, texture_buffer->driver_id, p_name);6198} else if (storage_buffer_owner.owns(p_id)) {6199Buffer *storage_buffer = storage_buffer_owner.get_or_null(p_id);6200driver->set_object_name(RDD::OBJECT_TYPE_BUFFER, storage_buffer->driver_id, p_name);6201} else if (uniform_set_owner.owns(p_id)) {6202UniformSet *uniform_set = uniform_set_owner.get_or_null(p_id);6203driver->set_object_name(RDD::OBJECT_TYPE_UNIFORM_SET, uniform_set->driver_id, p_name);6204} else if (render_pipeline_owner.owns(p_id)) {6205RenderPipeline *pipeline = render_pipeline_owner.get_or_null(p_id);6206driver->set_object_name(RDD::OBJECT_TYPE_PIPELINE, pipeline->driver_id, p_name);6207} else if (compute_pipeline_owner.owns(p_id)) {6208ComputePipeline *pipeline = compute_pipeline_owner.get_or_null(p_id);6209driver->set_object_name(RDD::OBJECT_TYPE_PIPELINE, pipeline->driver_id, p_name);6210} else {6211ERR_PRINT("Attempted to name invalid ID: " + itos(p_id.get_id()));6212return;6213}6214#ifdef DEV_ENABLED6215resource_names[p_id] = p_name;6216#endif6217}62186219void RenderingDevice::_draw_command_begin_label(String p_label_name, const Color &p_color) {6220draw_command_begin_label(p_label_name.utf8().span(), p_color);6221}62226223void RenderingDevice::draw_command_begin_label(const Span<char> p_label_name, const Color &p_color) {6224ERR_RENDER_THREAD_GUARD();62256226if (!context->is_debug_utils_enabled()) {6227return;6228}62296230draw_graph.begin_label(p_label_name, p_color);6231}62326233#ifndef DISABLE_DEPRECATED6234void RenderingDevice::draw_command_insert_label(String p_label_name, const Color &p_color) {6235WARN_PRINT("Deprecated. Inserting labels no longer applies due to command reordering.");6236}6237#endif62386239void RenderingDevice::draw_command_end_label() {6240ERR_RENDER_THREAD_GUARD();62416242draw_graph.end_label();6243}62446245String RenderingDevice::get_device_vendor_name() const {6246return _get_device_vendor_name(device);6247}62486249String RenderingDevice::get_device_name() const {6250return device.name;6251}62526253RenderingDevice::DeviceType RenderingDevice::get_device_type() const {6254return DeviceType(device.type);6255}62566257String RenderingDevice::get_device_api_name() const {6258return driver->get_api_name();6259}62606261bool RenderingDevice::is_composite_alpha_supported() const {6262return driver->is_composite_alpha_supported(main_queue);6263}62646265String RenderingDevice::get_device_api_version() const {6266return driver->get_api_version();6267}62686269String RenderingDevice::get_device_pipeline_cache_uuid() const {6270return driver->get_pipeline_cache_uuid();6271}62726273void RenderingDevice::swap_buffers(bool p_present) {6274ERR_RENDER_THREAD_GUARD();62756276_end_frame();6277_execute_frame(p_present);62786279// Advance to the next frame and begin recording again.6280frame = (frame + 1) % frames.size();62816282_begin_frame(true);6283}62846285void RenderingDevice::submit() {6286ERR_RENDER_THREAD_GUARD();6287ERR_FAIL_COND_MSG(is_main_instance, "Only local devices can submit and sync.");6288ERR_FAIL_COND_MSG(local_device_processing, "device already submitted, call sync to wait until done.");62896290_end_frame();6291_execute_frame(false);6292local_device_processing = true;6293}62946295void RenderingDevice::sync() {6296ERR_RENDER_THREAD_GUARD();6297ERR_FAIL_COND_MSG(is_main_instance, "Only local devices can submit and sync.");6298ERR_FAIL_COND_MSG(!local_device_processing, "sync can only be called after a submit");62996300_begin_frame(true);6301local_device_processing = false;6302}63036304void RenderingDevice::_free_pending_resources(int p_frame) {6305// Free in dependency usage order, so nothing weird happens.6306// Pipelines.6307while (frames[p_frame].render_pipelines_to_dispose_of.front()) {6308RenderPipeline *pipeline = &frames[p_frame].render_pipelines_to_dispose_of.front()->get();63096310driver->pipeline_free(pipeline->driver_id);63116312frames[p_frame].render_pipelines_to_dispose_of.pop_front();6313}63146315while (frames[p_frame].compute_pipelines_to_dispose_of.front()) {6316ComputePipeline *pipeline = &frames[p_frame].compute_pipelines_to_dispose_of.front()->get();63176318driver->pipeline_free(pipeline->driver_id);63196320frames[p_frame].compute_pipelines_to_dispose_of.pop_front();6321}63226323// Uniform sets.6324while (frames[p_frame].uniform_sets_to_dispose_of.front()) {6325UniformSet *uniform_set = &frames[p_frame].uniform_sets_to_dispose_of.front()->get();63266327driver->uniform_set_free(uniform_set->driver_id);63286329frames[p_frame].uniform_sets_to_dispose_of.pop_front();6330}63316332// Shaders.6333while (frames[p_frame].shaders_to_dispose_of.front()) {6334Shader *shader = &frames[p_frame].shaders_to_dispose_of.front()->get();63356336driver->shader_free(shader->driver_id);63376338frames[p_frame].shaders_to_dispose_of.pop_front();6339}63406341// Samplers.6342while (frames[p_frame].samplers_to_dispose_of.front()) {6343RDD::SamplerID sampler = frames[p_frame].samplers_to_dispose_of.front()->get();63446345driver->sampler_free(sampler);63466347frames[p_frame].samplers_to_dispose_of.pop_front();6348}63496350// Framebuffers.6351while (frames[p_frame].framebuffers_to_dispose_of.front()) {6352Framebuffer *framebuffer = &frames[p_frame].framebuffers_to_dispose_of.front()->get();6353draw_graph.framebuffer_cache_free(driver, framebuffer->framebuffer_cache);6354frames[p_frame].framebuffers_to_dispose_of.pop_front();6355}63566357// Textures.6358while (frames[p_frame].textures_to_dispose_of.front()) {6359Texture *texture = &frames[p_frame].textures_to_dispose_of.front()->get();6360if (texture->bound) {6361WARN_PRINT("Deleted a texture while it was bound.");6362}63636364_texture_free_shared_fallback(texture);63656366texture_memory -= driver->texture_get_allocation_size(texture->driver_id);6367driver->texture_free(texture->driver_id);63686369frames[p_frame].textures_to_dispose_of.pop_front();6370}63716372// Buffers.6373while (frames[p_frame].buffers_to_dispose_of.front()) {6374Buffer &buffer = frames[p_frame].buffers_to_dispose_of.front()->get();6375driver->buffer_free(buffer.driver_id);6376buffer_memory -= buffer.size;63776378frames[p_frame].buffers_to_dispose_of.pop_front();6379}63806381if (frames_pending_resources_for_processing > 0u) {6382--frames_pending_resources_for_processing;6383}6384}63856386uint32_t RenderingDevice::get_frame_delay() const {6387return frames.size();6388}63896390uint64_t RenderingDevice::get_memory_usage(MemoryType p_type) const {6391switch (p_type) {6392case MEMORY_BUFFERS: {6393return buffer_memory;6394}6395case MEMORY_TEXTURES: {6396return texture_memory;6397}6398case MEMORY_TOTAL: {6399return driver->get_total_memory_used();6400}6401default: {6402DEV_ASSERT(false);6403return 0;6404}6405}6406}64076408void RenderingDevice::_begin_frame(bool p_presented) {6409// Before writing to this frame, wait for it to be finished.6410_stall_for_frame(frame);64116412if (command_pool_reset_enabled) {6413bool reset = driver->command_pool_reset(frames[frame].command_pool);6414ERR_FAIL_COND(!reset);6415}64166417if (p_presented) {6418update_perf_report();6419driver->linear_uniform_set_pools_reset(frame);6420}64216422// Begin recording on the frame's command buffers.6423driver->begin_segment(frame, frames_drawn++);6424driver->command_buffer_begin(frames[frame].command_buffer);64256426// Reset the graph.6427draw_graph.begin();64286429// Erase pending resources.6430_free_pending_resources(frame);64316432// Advance staging buffers if used.6433if (upload_staging_buffers.used) {6434upload_staging_buffers.current = (upload_staging_buffers.current + 1) % upload_staging_buffers.blocks.size();6435upload_staging_buffers.used = false;6436}64376438if (download_staging_buffers.used) {6439download_staging_buffers.current = (download_staging_buffers.current + 1) % download_staging_buffers.blocks.size();6440download_staging_buffers.used = false;6441}64426443if (frames[frame].timestamp_count) {6444driver->timestamp_query_pool_get_results(frames[frame].timestamp_pool, frames[frame].timestamp_count, frames[frame].timestamp_result_values.ptr());6445driver->command_timestamp_query_pool_reset(frames[frame].command_buffer, frames[frame].timestamp_pool, frames[frame].timestamp_count);6446SWAP(frames[frame].timestamp_names, frames[frame].timestamp_result_names);6447SWAP(frames[frame].timestamp_cpu_values, frames[frame].timestamp_cpu_result_values);6448}64496450frames[frame].timestamp_result_count = frames[frame].timestamp_count;6451frames[frame].timestamp_count = 0;6452frames[frame].index = Engine::get_singleton()->get_frames_drawn();6453}64546455void RenderingDevice::_end_frame() {6456if (draw_list.active) {6457ERR_PRINT("Found open draw list at the end of the frame, this should never happen (further drawing will likely not work).");6458}64596460if (compute_list.active) {6461ERR_PRINT("Found open compute list at the end of the frame, this should never happen (further compute will likely not work).");6462}64636464// The command buffer must be copied into a stack variable as the driver workarounds can change the command buffer in use.6465RDD::CommandBufferID command_buffer = frames[frame].command_buffer;6466_submit_transfer_workers(command_buffer);6467_submit_transfer_barriers(command_buffer);64686469draw_graph.end(RENDER_GRAPH_REORDER, RENDER_GRAPH_FULL_BARRIERS, command_buffer, frames[frame].command_buffer_pool);6470driver->command_buffer_end(command_buffer);6471driver->end_segment();6472}64736474void RenderingDevice::execute_chained_cmds(bool p_present_swap_chain, RenderingDeviceDriver::FenceID p_draw_fence,6475RenderingDeviceDriver::SemaphoreID p_dst_draw_semaphore_to_signal) {6476// Execute command buffers and use semaphores to wait on the execution of the previous one.6477// Normally there's only one command buffer, but driver workarounds can force situations where6478// there'll be more.6479uint32_t command_buffer_count = 1;6480RDG::CommandBufferPool &buffer_pool = frames[frame].command_buffer_pool;6481if (buffer_pool.buffers_used > 0) {6482command_buffer_count += buffer_pool.buffers_used;6483buffer_pool.buffers_used = 0;6484}64856486thread_local LocalVector<RDD::SwapChainID> swap_chains;6487swap_chains.clear();64886489// Instead of having just one command; we have potentially many (which had to be split due to an6490// Adreno workaround on mobile, only if the workaround is active). Thus we must execute all of them6491// and chain them together via semaphores as dependent executions.6492thread_local LocalVector<RDD::SemaphoreID> wait_semaphores;6493wait_semaphores = frames[frame].semaphores_to_wait_on;64946495for (uint32_t i = 0; i < command_buffer_count; i++) {6496RDD::CommandBufferID command_buffer;6497RDD::SemaphoreID signal_semaphore;6498RDD::FenceID signal_fence;6499if (i > 0) {6500command_buffer = buffer_pool.buffers[i - 1];6501} else {6502command_buffer = frames[frame].command_buffer;6503}65046505if (i == (command_buffer_count - 1)) {6506// This is the last command buffer, it should signal the semaphore & fence.6507signal_semaphore = p_dst_draw_semaphore_to_signal;6508signal_fence = p_draw_fence;65096510if (p_present_swap_chain) {6511// Just present the swap chains as part of the last command execution.6512swap_chains = frames[frame].swap_chains_to_present;6513}6514} else {6515signal_semaphore = buffer_pool.semaphores[i];6516// Semaphores always need to be signaled if it's not the last command buffer.6517}65186519driver->command_queue_execute_and_present(main_queue, wait_semaphores, command_buffer,6520signal_semaphore ? signal_semaphore : VectorView<RDD::SemaphoreID>(), signal_fence,6521swap_chains);65226523// Make the next command buffer wait on the semaphore signaled by this one.6524wait_semaphores.resize(1);6525wait_semaphores[0] = signal_semaphore;6526}65276528frames[frame].semaphores_to_wait_on.clear();6529}65306531void RenderingDevice::_execute_frame(bool p_present) {6532// Check whether this frame should present the swap chains and in which queue.6533const bool frame_can_present = p_present && !frames[frame].swap_chains_to_present.is_empty();6534const bool separate_present_queue = main_queue != present_queue;65356536// The semaphore is required if the frame can be presented and a separate present queue is used;6537// since the separate queue will wait for that semaphore before presenting.6538const RDD::SemaphoreID semaphore = (frame_can_present && separate_present_queue)6539? frames[frame].semaphore6540: RDD::SemaphoreID(nullptr);6541const bool present_swap_chain = frame_can_present && !separate_present_queue;65426543execute_chained_cmds(present_swap_chain, frames[frame].fence, semaphore);6544// Indicate the fence has been signaled so the next time the frame's contents need to be6545// used, the CPU needs to wait on the work to be completed.6546frames[frame].fence_signaled = true;65476548if (frame_can_present) {6549if (separate_present_queue) {6550// Issue the presentation separately if the presentation queue is different from the main queue.6551driver->command_queue_execute_and_present(present_queue, frames[frame].semaphore, {}, {}, {}, frames[frame].swap_chains_to_present);6552}65536554frames[frame].swap_chains_to_present.clear();6555}6556}65576558void RenderingDevice::_stall_for_frame(uint32_t p_frame) {6559thread_local PackedByteArray packed_byte_array;65606561if (frames[p_frame].fence_signaled) {6562driver->fence_wait(frames[p_frame].fence);6563frames[p_frame].fence_signaled = false;65646565// Flush any pending requests for asynchronous buffer downloads.6566if (!frames[p_frame].download_buffer_get_data_requests.is_empty()) {6567for (uint32_t i = 0; i < frames[p_frame].download_buffer_get_data_requests.size(); i++) {6568const BufferGetDataRequest &request = frames[p_frame].download_buffer_get_data_requests[i];6569packed_byte_array.resize(request.size);65706571uint32_t array_offset = 0;6572for (uint32_t j = 0; j < request.frame_local_count; j++) {6573uint32_t local_index = request.frame_local_index + j;6574const RDD::BufferCopyRegion ®ion = frames[p_frame].download_buffer_copy_regions[local_index];6575uint8_t *buffer_data = driver->buffer_map(frames[p_frame].download_buffer_staging_buffers[local_index]);6576memcpy(&packed_byte_array.write[array_offset], &buffer_data[region.dst_offset], region.size);6577driver->buffer_unmap(frames[p_frame].download_buffer_staging_buffers[local_index]);6578array_offset += region.size;6579}65806581request.callback.call(packed_byte_array);6582}65836584frames[p_frame].download_buffer_staging_buffers.clear();6585frames[p_frame].download_buffer_copy_regions.clear();6586frames[p_frame].download_buffer_get_data_requests.clear();6587}65886589// Flush any pending requests for asynchronous texture downloads.6590if (!frames[p_frame].download_texture_get_data_requests.is_empty()) {6591uint32_t pitch_step = driver->api_trait_get(RDD::API_TRAIT_TEXTURE_DATA_ROW_PITCH_STEP);6592for (uint32_t i = 0; i < frames[p_frame].download_texture_get_data_requests.size(); i++) {6593const TextureGetDataRequest &request = frames[p_frame].download_texture_get_data_requests[i];6594uint32_t texture_size = get_image_format_required_size(request.format, request.width, request.height, request.depth, request.mipmaps);6595packed_byte_array.resize(texture_size);65966597// Find the block size of the texture's format.6598uint32_t block_w = 0;6599uint32_t block_h = 0;6600get_compressed_image_format_block_dimensions(request.format, block_w, block_h);66016602uint32_t block_size = get_compressed_image_format_block_byte_size(request.format);6603uint32_t pixel_size = get_image_format_pixel_size(request.format);6604uint32_t pixel_rshift = get_compressed_image_format_pixel_rshift(request.format);6605uint32_t region_size = texture_download_region_size_px;66066607for (uint32_t j = 0; j < request.frame_local_count; j++) {6608uint32_t local_index = request.frame_local_index + j;6609const RDD::BufferTextureCopyRegion ®ion = frames[p_frame].download_buffer_texture_copy_regions[local_index];6610uint32_t w = STEPIFY(request.width >> region.texture_subresources.mipmap, block_w);6611uint32_t h = STEPIFY(request.height >> region.texture_subresources.mipmap, block_h);6612uint32_t region_w = MIN(region_size, w - region.texture_offset.x);6613uint32_t region_h = MIN(region_size, h - region.texture_offset.y);6614uint32_t region_pitch = (region_w * pixel_size * block_w) >> pixel_rshift;6615region_pitch = STEPIFY(region_pitch, pitch_step);66166617uint8_t *buffer_data = driver->buffer_map(frames[p_frame].download_texture_staging_buffers[local_index]);6618const uint8_t *read_ptr = buffer_data + region.buffer_offset;6619uint8_t *write_ptr = packed_byte_array.ptrw() + frames[p_frame].download_texture_mipmap_offsets[local_index];6620uint32_t unit_size = pixel_size;6621if (block_w != 1 || block_h != 1) {6622unit_size = block_size;6623}66246625write_ptr += ((region.texture_offset.y / block_h) * (w / block_w) + (region.texture_offset.x / block_w)) * unit_size;6626for (uint32_t y = region_h / block_h; y > 0; y--) {6627memcpy(write_ptr, read_ptr, (region_w / block_w) * unit_size);6628write_ptr += (w / block_w) * unit_size;6629read_ptr += region_pitch;6630}66316632driver->buffer_unmap(frames[p_frame].download_texture_staging_buffers[local_index]);6633}66346635request.callback.call(packed_byte_array);6636}66376638frames[p_frame].download_texture_staging_buffers.clear();6639frames[p_frame].download_buffer_texture_copy_regions.clear();6640frames[p_frame].download_texture_mipmap_offsets.clear();6641frames[p_frame].download_texture_get_data_requests.clear();6642}6643}6644}66456646void RenderingDevice::_stall_for_previous_frames() {6647for (uint32_t i = 0; i < frames.size(); i++) {6648_stall_for_frame(i);6649}6650}66516652void RenderingDevice::_flush_and_stall_for_all_frames() {6653_stall_for_previous_frames();6654_end_frame();6655_execute_frame(false);6656_begin_frame();6657}66586659Error RenderingDevice::initialize(RenderingContextDriver *p_context, DisplayServer::WindowID p_main_window) {6660ERR_RENDER_THREAD_GUARD_V(ERR_UNAVAILABLE);66616662Error err;6663RenderingContextDriver::SurfaceID main_surface = 0;6664is_main_instance = (singleton == this) && (p_main_window != DisplayServer::INVALID_WINDOW_ID);6665if (p_main_window != DisplayServer::INVALID_WINDOW_ID) {6666// Retrieve the surface from the main window if it was specified.6667main_surface = p_context->surface_get_from_window(p_main_window);6668ERR_FAIL_COND_V(main_surface == 0, FAILED);6669}66706671context = p_context;6672driver = context->driver_create();66736674print_verbose("Devices:");6675int32_t device_index = Engine::get_singleton()->get_gpu_index();6676const uint32_t device_count = context->device_get_count();6677const bool detect_device = (device_index < 0) || (device_index >= int32_t(device_count));6678uint32_t device_type_score = 0;6679for (uint32_t i = 0; i < device_count; i++) {6680RenderingContextDriver::Device device_option = context->device_get(i);6681String name = device_option.name;6682String vendor = _get_device_vendor_name(device_option);6683String type = _get_device_type_name(device_option);6684bool present_supported = main_surface != 0 ? context->device_supports_present(i, main_surface) : false;6685print_verbose(" #" + itos(i) + ": " + vendor + " " + name + " - " + (present_supported ? "Supported" : "Unsupported") + ", " + type);6686if (detect_device && (present_supported || main_surface == 0)) {6687// If a window was specified, present must be supported by the device to be available as an option.6688// Assign a score for each type of device and prefer the device with the higher score.6689uint32_t option_score = _get_device_type_score(device_option);6690if (option_score > device_type_score) {6691device_index = i;6692device_type_score = option_score;6693}6694}6695}66966697ERR_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.");66986699uint32_t frame_count = 1;6700if (main_surface != 0) {6701frame_count = MAX(2U, uint32_t(GLOBAL_GET("rendering/rendering_device/vsync/frame_queue_size")));6702}67036704frame = 0;6705max_timestamp_query_elements = GLOBAL_GET("debug/settings/profiler/max_timestamp_query_elements");67066707device = context->device_get(device_index);6708err = driver->initialize(device_index, frame_count);6709ERR_FAIL_COND_V_MSG(err != OK, FAILED, "Failed to initialize driver for device.");67106711if (is_main_instance) {6712// Only the singleton instance with a display should print this information.6713String rendering_method;6714if (OS::get_singleton()->get_current_rendering_method() == "mobile") {6715rendering_method = "Forward Mobile";6716} else {6717rendering_method = "Forward+";6718}67196720// Output our device version.6721Engine::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));6722}67236724// Pick the main queue family. It is worth noting we explicitly do not request the transfer bit, as apparently the specification defines6725// that the existence of either the graphics or compute bit implies that the queue can also do transfer operations, but it is optional6726// to indicate whether it supports them or not with the dedicated transfer bit if either is set.6727BitField<RDD::CommandQueueFamilyBits> main_queue_bits = {};6728main_queue_bits.set_flag(RDD::COMMAND_QUEUE_FAMILY_GRAPHICS_BIT);6729main_queue_bits.set_flag(RDD::COMMAND_QUEUE_FAMILY_COMPUTE_BIT);67306731#if !FORCE_SEPARATE_PRESENT_QUEUE6732// Needing to use a separate queue for presentation is an edge case that remains to be seen what hardware triggers it at all.6733main_queue_family = driver->command_queue_family_get(main_queue_bits, main_surface);6734if (!main_queue_family && (main_surface != 0))6735#endif6736{6737// If it was not possible to find a main queue that supports the surface, we attempt to get two different queues instead.6738main_queue_family = driver->command_queue_family_get(main_queue_bits);6739present_queue_family = driver->command_queue_family_get(BitField<RDD::CommandQueueFamilyBits>(), main_surface);6740ERR_FAIL_COND_V(!present_queue_family, FAILED);6741}67426743ERR_FAIL_COND_V(!main_queue_family, FAILED);67446745// Create the main queue.6746main_queue = driver->command_queue_create(main_queue_family, true);6747ERR_FAIL_COND_V(!main_queue, FAILED);67486749transfer_queue_family = driver->command_queue_family_get(RDD::COMMAND_QUEUE_FAMILY_TRANSFER_BIT);6750if (transfer_queue_family) {6751// Create the transfer queue.6752transfer_queue = driver->command_queue_create(transfer_queue_family);6753ERR_FAIL_COND_V(!transfer_queue, FAILED);6754} else {6755// Use main queue as the transfer queue.6756transfer_queue = main_queue;6757transfer_queue_family = main_queue_family;6758}67596760if (present_queue_family) {6761// Create the present queue.6762present_queue = driver->command_queue_create(present_queue_family);6763ERR_FAIL_COND_V(!present_queue, FAILED);6764} else {6765// Use main queue as the present queue.6766present_queue = main_queue;6767present_queue_family = main_queue_family;6768}67696770// Use the processor count as the max amount of transfer workers that can be created.6771transfer_worker_pool_max_size = OS::get_singleton()->get_processor_count();67726773frames.resize(frame_count);67746775// Create data for all the frames.6776for (uint32_t i = 0; i < frames.size(); i++) {6777frames[i].index = 0;67786779// Create command pool, command buffers, semaphores and fences.6780frames[i].command_pool = driver->command_pool_create(main_queue_family, RDD::COMMAND_BUFFER_TYPE_PRIMARY);6781ERR_FAIL_COND_V(!frames[i].command_pool, FAILED);6782frames[i].command_buffer = driver->command_buffer_create(frames[i].command_pool);6783ERR_FAIL_COND_V(!frames[i].command_buffer, FAILED);6784frames[i].semaphore = driver->semaphore_create();6785ERR_FAIL_COND_V(!frames[i].semaphore, FAILED);6786frames[i].fence = driver->fence_create();6787ERR_FAIL_COND_V(!frames[i].fence, FAILED);6788frames[i].fence_signaled = false;67896790// Create query pool.6791frames[i].timestamp_pool = driver->timestamp_query_pool_create(max_timestamp_query_elements);6792frames[i].timestamp_names.resize(max_timestamp_query_elements);6793frames[i].timestamp_cpu_values.resize(max_timestamp_query_elements);6794frames[i].timestamp_count = 0;6795frames[i].timestamp_result_names.resize(max_timestamp_query_elements);6796frames[i].timestamp_cpu_result_values.resize(max_timestamp_query_elements);6797frames[i].timestamp_result_values.resize(max_timestamp_query_elements);6798frames[i].timestamp_result_count = 0;67996800// Assign the main queue family and command pool to the command buffer pool.6801frames[i].command_buffer_pool.pool = frames[i].command_pool;68026803// Create the semaphores for the transfer workers.6804frames[i].transfer_worker_semaphores.resize(transfer_worker_pool_max_size);6805for (uint32_t j = 0; j < transfer_worker_pool_max_size; j++) {6806frames[i].transfer_worker_semaphores[j] = driver->semaphore_create();6807ERR_FAIL_COND_V(!frames[i].transfer_worker_semaphores[j], FAILED);6808}6809}68106811// Start from frame count, so everything else is immediately old.6812frames_drawn = frames.size();68136814// Initialize recording on the first frame.6815driver->begin_segment(frame, frames_drawn++);6816driver->command_buffer_begin(frames[0].command_buffer);68176818// Create draw graph and start it initialized as well.6819draw_graph.initialize(driver, device, &_render_pass_create_from_graph, frames.size(), main_queue_family, SECONDARY_COMMAND_BUFFERS_PER_FRAME);6820draw_graph.begin();68216822for (uint32_t i = 0; i < frames.size(); i++) {6823// Reset all queries in a query pool before doing any operations with them..6824driver->command_timestamp_query_pool_reset(frames[0].command_buffer, frames[i].timestamp_pool, max_timestamp_query_elements);6825}68266827// Convert block size from KB.6828upload_staging_buffers.block_size = GLOBAL_GET("rendering/rendering_device/staging_buffer/block_size_kb");6829upload_staging_buffers.block_size = MAX(4u, upload_staging_buffers.block_size);6830upload_staging_buffers.block_size *= 1024;68316832// Convert staging buffer size from MB.6833upload_staging_buffers.max_size = GLOBAL_GET("rendering/rendering_device/staging_buffer/max_size_mb");6834upload_staging_buffers.max_size = MAX(1u, upload_staging_buffers.max_size);6835upload_staging_buffers.max_size *= 1024 * 1024;6836upload_staging_buffers.max_size = MAX(upload_staging_buffers.max_size, upload_staging_buffers.block_size * 4);68376838// Copy the sizes to the download staging buffers.6839download_staging_buffers.block_size = upload_staging_buffers.block_size;6840download_staging_buffers.max_size = upload_staging_buffers.max_size;68416842texture_upload_region_size_px = GLOBAL_GET("rendering/rendering_device/staging_buffer/texture_upload_region_size_px");6843texture_upload_region_size_px = nearest_power_of_2_templated(texture_upload_region_size_px);68446845texture_download_region_size_px = GLOBAL_GET("rendering/rendering_device/staging_buffer/texture_download_region_size_px");6846texture_download_region_size_px = nearest_power_of_2_templated(texture_download_region_size_px);68476848// Ensure current staging block is valid and at least one per frame exists.6849upload_staging_buffers.current = 0;6850upload_staging_buffers.used = false;6851upload_staging_buffers.usage_bits = RDD::BUFFER_USAGE_TRANSFER_FROM_BIT;68526853download_staging_buffers.current = 0;6854download_staging_buffers.used = false;6855download_staging_buffers.usage_bits = RDD::BUFFER_USAGE_TRANSFER_TO_BIT;68566857for (uint32_t i = 0; i < frames.size(); i++) {6858// Staging was never used, create the blocks.6859err = _insert_staging_block(upload_staging_buffers);6860ERR_FAIL_COND_V(err, FAILED);68616862err = _insert_staging_block(download_staging_buffers);6863ERR_FAIL_COND_V(err, FAILED);6864}68656866draw_list = DrawList();6867compute_list = ComputeList();68686869bool project_pipeline_cache_enable = GLOBAL_GET("rendering/rendering_device/pipeline_cache/enable");6870if (is_main_instance && project_pipeline_cache_enable) {6871// Only the instance that is not a local device and is also the singleton is allowed to manage a pipeline cache.6872pipeline_cache_file_path = vformat("user://vulkan/pipelines.%s.%s",6873OS::get_singleton()->get_current_rendering_method(),6874device.name.validate_filename().replace_char(' ', '_').to_lower());6875if (Engine::get_singleton()->is_editor_hint()) {6876pipeline_cache_file_path += ".editor";6877}6878pipeline_cache_file_path += ".cache";68796880Vector<uint8_t> cache_data = _load_pipeline_cache();6881pipeline_cache_enabled = driver->pipeline_cache_create(cache_data);6882if (pipeline_cache_enabled) {6883pipeline_cache_size = driver->pipeline_cache_query_size();6884print_verbose(vformat("Startup PSO cache (%.1f MiB)", pipeline_cache_size / (1024.0f * 1024.0f)));6885}6886}68876888// Find the best method available for VRS on the current hardware.6889_vrs_detect_method();68906891return OK;6892}68936894Vector<uint8_t> RenderingDevice::_load_pipeline_cache() {6895DirAccess::make_dir_recursive_absolute(pipeline_cache_file_path.get_base_dir());68966897if (FileAccess::exists(pipeline_cache_file_path)) {6898Error file_error;6899Vector<uint8_t> file_data = FileAccess::get_file_as_bytes(pipeline_cache_file_path, &file_error);6900return file_data;6901} else {6902return Vector<uint8_t>();6903}6904}69056906void RenderingDevice::_update_pipeline_cache(bool p_closing) {6907_THREAD_SAFE_METHOD_69086909{6910bool still_saving = pipeline_cache_save_task != WorkerThreadPool::INVALID_TASK_ID && !WorkerThreadPool::get_singleton()->is_task_completed(pipeline_cache_save_task);6911if (still_saving) {6912if (p_closing) {6913WorkerThreadPool::get_singleton()->wait_for_task_completion(pipeline_cache_save_task);6914pipeline_cache_save_task = WorkerThreadPool::INVALID_TASK_ID;6915} else {6916// We can't save until the currently running save is done. We'll retry next time; worst case, we'll save when exiting.6917return;6918}6919}6920}69216922{6923size_t new_pipelines_cache_size = driver->pipeline_cache_query_size();6924ERR_FAIL_COND(!new_pipelines_cache_size);6925size_t difference = new_pipelines_cache_size - pipeline_cache_size;69266927bool must_save = false;69286929if (p_closing) {6930must_save = difference > 0;6931} else {6932float save_interval = GLOBAL_GET("rendering/rendering_device/pipeline_cache/save_chunk_size_mb");6933must_save = difference > 0 && difference / (1024.0f * 1024.0f) >= save_interval;6934}69356936if (must_save) {6937pipeline_cache_size = new_pipelines_cache_size;6938} else {6939return;6940}6941}69426943if (p_closing) {6944_save_pipeline_cache(this);6945} else {6946pipeline_cache_save_task = WorkerThreadPool::get_singleton()->add_native_task(&_save_pipeline_cache, this, false, "PipelineCacheSave");6947}6948}69496950void RenderingDevice::_save_pipeline_cache(void *p_data) {6951RenderingDevice *self = static_cast<RenderingDevice *>(p_data);69526953self->_thread_safe_.lock();6954Vector<uint8_t> cache_blob = self->driver->pipeline_cache_serialize();6955self->_thread_safe_.unlock();69566957if (cache_blob.is_empty()) {6958return;6959}6960print_verbose(vformat("Updated PSO cache (%.1f MiB)", cache_blob.size() / (1024.0f * 1024.0f)));69616962Ref<FileAccess> f = FileAccess::open(self->pipeline_cache_file_path, FileAccess::WRITE, nullptr);6963if (f.is_valid()) {6964f->store_buffer(cache_blob);6965}6966}69676968template <typename T>6969void RenderingDevice::_free_rids(T &p_owner, const char *p_type) {6970LocalVector<RID> owned = p_owner.get_owned_list();6971if (owned.size()) {6972if (owned.size() == 1) {6973WARN_PRINT(vformat("1 RID of type \"%s\" was leaked.", p_type));6974} else {6975WARN_PRINT(vformat("%d RIDs of type \"%s\" were leaked.", owned.size(), p_type));6976}6977for (const RID &rid : owned) {6978#ifdef DEV_ENABLED6979if (resource_names.has(rid)) {6980print_line(String(" - ") + resource_names[rid]);6981}6982#endif6983free_rid(rid);6984}6985}6986}69876988void RenderingDevice::capture_timestamp(const String &p_name) {6989ERR_RENDER_THREAD_GUARD();69906991ERR_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);6992ERR_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);6993ERR_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));69946995draw_graph.add_capture_timestamp(frames[frame].timestamp_pool, frames[frame].timestamp_count);69966997frames[frame].timestamp_names[frames[frame].timestamp_count] = p_name;6998frames[frame].timestamp_cpu_values[frames[frame].timestamp_count] = OS::get_singleton()->get_ticks_usec();6999frames[frame].timestamp_count++;7000}70017002uint64_t RenderingDevice::get_driver_resource(DriverResource p_resource, RID p_rid, uint64_t p_index) {7003ERR_RENDER_THREAD_GUARD_V(0);70047005uint64_t driver_id = 0;7006switch (p_resource) {7007case DRIVER_RESOURCE_LOGICAL_DEVICE:7008case DRIVER_RESOURCE_PHYSICAL_DEVICE:7009case DRIVER_RESOURCE_TOPMOST_OBJECT:7010break;7011case DRIVER_RESOURCE_COMMAND_QUEUE:7012driver_id = main_queue.id;7013break;7014case DRIVER_RESOURCE_QUEUE_FAMILY:7015driver_id = main_queue_family.id;7016break;7017case DRIVER_RESOURCE_TEXTURE:7018case DRIVER_RESOURCE_TEXTURE_VIEW:7019case DRIVER_RESOURCE_TEXTURE_DATA_FORMAT: {7020Texture *tex = texture_owner.get_or_null(p_rid);7021ERR_FAIL_NULL_V(tex, 0);70227023driver_id = tex->driver_id.id;7024} break;7025case DRIVER_RESOURCE_SAMPLER: {7026RDD::SamplerID *sampler_driver_id = sampler_owner.get_or_null(p_rid);7027ERR_FAIL_NULL_V(sampler_driver_id, 0);70287029driver_id = (*sampler_driver_id).id;7030} break;7031case DRIVER_RESOURCE_UNIFORM_SET: {7032UniformSet *uniform_set = uniform_set_owner.get_or_null(p_rid);7033ERR_FAIL_NULL_V(uniform_set, 0);70347035driver_id = uniform_set->driver_id.id;7036} break;7037case DRIVER_RESOURCE_BUFFER: {7038Buffer *buffer = nullptr;7039if (vertex_buffer_owner.owns(p_rid)) {7040buffer = vertex_buffer_owner.get_or_null(p_rid);7041} else if (index_buffer_owner.owns(p_rid)) {7042buffer = index_buffer_owner.get_or_null(p_rid);7043} else if (uniform_buffer_owner.owns(p_rid)) {7044buffer = uniform_buffer_owner.get_or_null(p_rid);7045} else if (texture_buffer_owner.owns(p_rid)) {7046buffer = texture_buffer_owner.get_or_null(p_rid);7047} else if (storage_buffer_owner.owns(p_rid)) {7048buffer = storage_buffer_owner.get_or_null(p_rid);7049}7050ERR_FAIL_NULL_V(buffer, 0);70517052driver_id = buffer->driver_id.id;7053} break;7054case DRIVER_RESOURCE_COMPUTE_PIPELINE: {7055ComputePipeline *compute_pipeline = compute_pipeline_owner.get_or_null(p_rid);7056ERR_FAIL_NULL_V(compute_pipeline, 0);70577058driver_id = compute_pipeline->driver_id.id;7059} break;7060case DRIVER_RESOURCE_RENDER_PIPELINE: {7061RenderPipeline *render_pipeline = render_pipeline_owner.get_or_null(p_rid);7062ERR_FAIL_NULL_V(render_pipeline, 0);70637064driver_id = render_pipeline->driver_id.id;7065} break;7066default: {7067ERR_FAIL_V(0);7068} break;7069}70707071return driver->get_resource_native_handle(p_resource, driver_id);7072}70737074String RenderingDevice::get_driver_and_device_memory_report() const {7075return context->get_driver_and_device_memory_report();7076}70777078String RenderingDevice::get_tracked_object_name(uint32_t p_type_index) const {7079return context->get_tracked_object_name(p_type_index);7080}70817082uint64_t RenderingDevice::get_tracked_object_type_count() const {7083return context->get_tracked_object_type_count();7084}70857086uint64_t RenderingDevice::get_driver_total_memory() const {7087return context->get_driver_total_memory();7088}70897090uint64_t RenderingDevice::get_driver_allocation_count() const {7091return context->get_driver_allocation_count();7092}70937094uint64_t RenderingDevice::get_driver_memory_by_object_type(uint32_t p_type) const {7095return context->get_driver_memory_by_object_type(p_type);7096}70977098uint64_t RenderingDevice::get_driver_allocs_by_object_type(uint32_t p_type) const {7099return context->get_driver_allocs_by_object_type(p_type);7100}71017102uint64_t RenderingDevice::get_device_total_memory() const {7103return context->get_device_total_memory();7104}71057106uint64_t RenderingDevice::get_device_allocation_count() const {7107return context->get_device_allocation_count();7108}71097110uint64_t RenderingDevice::get_device_memory_by_object_type(uint32_t type) const {7111return context->get_device_memory_by_object_type(type);7112}71137114uint64_t RenderingDevice::get_device_allocs_by_object_type(uint32_t type) const {7115return context->get_device_allocs_by_object_type(type);7116}71177118uint32_t RenderingDevice::get_captured_timestamps_count() const {7119ERR_RENDER_THREAD_GUARD_V(0);7120return frames[frame].timestamp_result_count;7121}71227123uint64_t RenderingDevice::get_captured_timestamps_frame() const {7124ERR_RENDER_THREAD_GUARD_V(0);7125return frames[frame].index;7126}71277128uint64_t RenderingDevice::get_captured_timestamp_gpu_time(uint32_t p_index) const {7129ERR_RENDER_THREAD_GUARD_V(0);7130ERR_FAIL_UNSIGNED_INDEX_V(p_index, frames[frame].timestamp_result_count, 0);7131return driver->timestamp_query_result_to_time(frames[frame].timestamp_result_values[p_index]);7132}71337134uint64_t RenderingDevice::get_captured_timestamp_cpu_time(uint32_t p_index) const {7135ERR_RENDER_THREAD_GUARD_V(0);7136ERR_FAIL_UNSIGNED_INDEX_V(p_index, frames[frame].timestamp_result_count, 0);7137return frames[frame].timestamp_cpu_result_values[p_index];7138}71397140String RenderingDevice::get_captured_timestamp_name(uint32_t p_index) const {7141ERR_FAIL_UNSIGNED_INDEX_V(p_index, frames[frame].timestamp_result_count, String());7142return frames[frame].timestamp_result_names[p_index];7143}71447145uint64_t RenderingDevice::limit_get(Limit p_limit) const {7146return driver->limit_get(p_limit);7147}71487149void RenderingDevice::finalize() {7150ERR_RENDER_THREAD_GUARD();71517152if (!frames.is_empty()) {7153// Wait for all frames to have finished rendering.7154_flush_and_stall_for_all_frames();7155}71567157// Wait for transfer workers to finish.7158_submit_transfer_workers();7159_wait_for_transfer_workers();71607161// Delete everything the graph has created.7162draw_graph.finalize();71637164// Free all resources.7165_free_rids(render_pipeline_owner, "Pipeline");7166_free_rids(compute_pipeline_owner, "Compute");7167_free_rids(uniform_set_owner, "UniformSet");7168_free_rids(texture_buffer_owner, "TextureBuffer");7169_free_rids(storage_buffer_owner, "StorageBuffer");7170_free_rids(uniform_buffer_owner, "UniformBuffer");7171_free_rids(shader_owner, "Shader");7172_free_rids(index_array_owner, "IndexArray");7173_free_rids(index_buffer_owner, "IndexBuffer");7174_free_rids(vertex_array_owner, "VertexArray");7175_free_rids(vertex_buffer_owner, "VertexBuffer");7176_free_rids(framebuffer_owner, "Framebuffer");7177_free_rids(sampler_owner, "Sampler");7178{7179// For textures it's a bit more difficult because they may be shared.7180LocalVector<RID> owned = texture_owner.get_owned_list();7181if (owned.size()) {7182if (owned.size() == 1) {7183WARN_PRINT("1 RID of type \"Texture\" was leaked.");7184} else {7185WARN_PRINT(vformat("%d RIDs of type \"Texture\" were leaked.", owned.size()));7186}7187LocalVector<RID> owned_non_shared;7188// Free shared first.7189for (const RID &texture_rid : owned) {7190if (texture_is_shared(texture_rid)) {7191#ifdef DEV_ENABLED7192if (resource_names.has(texture_rid)) {7193print_line(String(" - ") + resource_names[texture_rid]);7194}7195#endif7196free_rid(texture_rid);7197} else {7198owned_non_shared.push_back(texture_rid);7199}7200}7201// Free non shared second, this will avoid an error trying to free unexisting textures due to dependencies.7202for (const RID &texture_rid : owned_non_shared) {7203#ifdef DEV_ENABLED7204if (resource_names.has(texture_rid)) {7205print_line(String(" - ") + resource_names[texture_rid]);7206}7207#endif7208free_rid(texture_rid);7209}7210}7211}72127213// Erase the transfer workers after all resources have been freed.7214_free_transfer_workers();72157216// Free everything pending.7217for (uint32_t i = 0; i < frames.size(); i++) {7218int f = (frame + i) % frames.size();7219_free_pending_resources(f);7220driver->command_pool_free(frames[i].command_pool);7221driver->timestamp_query_pool_free(frames[i].timestamp_pool);7222driver->semaphore_free(frames[i].semaphore);7223driver->fence_free(frames[i].fence);72247225RDG::CommandBufferPool &buffer_pool = frames[i].command_buffer_pool;7226for (uint32_t j = 0; j < buffer_pool.buffers.size(); j++) {7227driver->semaphore_free(buffer_pool.semaphores[j]);7228}72297230for (uint32_t j = 0; j < frames[i].transfer_worker_semaphores.size(); j++) {7231driver->semaphore_free(frames[i].transfer_worker_semaphores[j]);7232}7233}72347235if (pipeline_cache_enabled) {7236_update_pipeline_cache(true);7237driver->pipeline_cache_free();7238}72397240frames.clear();72417242for (int i = 0; i < upload_staging_buffers.blocks.size(); i++) {7243driver->buffer_free(upload_staging_buffers.blocks[i].driver_id);7244}72457246for (int i = 0; i < download_staging_buffers.blocks.size(); i++) {7247driver->buffer_free(download_staging_buffers.blocks[i].driver_id);7248}72497250while (vertex_formats.size()) {7251HashMap<VertexFormatID, VertexDescriptionCache>::Iterator temp = vertex_formats.begin();7252driver->vertex_format_free(temp->value.driver_id);7253vertex_formats.remove(temp);7254}72557256for (KeyValue<FramebufferFormatID, FramebufferFormat> &E : framebuffer_formats) {7257driver->render_pass_free(E.value.render_pass);7258}7259framebuffer_formats.clear();72607261// Delete the swap chains created for the screens.7262for (const KeyValue<DisplayServer::WindowID, RDD::SwapChainID> &it : screen_swap_chains) {7263driver->swap_chain_free(it.value);7264}72657266screen_swap_chains.clear();72677268// Delete the command queues.7269if (present_queue) {7270if (main_queue != present_queue) {7271// Only delete the present queue if it's unique.7272driver->command_queue_free(present_queue);7273}72747275present_queue = RDD::CommandQueueID();7276}72777278if (transfer_queue) {7279if (main_queue != transfer_queue) {7280// Only delete the transfer queue if it's unique.7281driver->command_queue_free(transfer_queue);7282}72837284transfer_queue = RDD::CommandQueueID();7285}72867287if (main_queue) {7288driver->command_queue_free(main_queue);7289main_queue = RDD::CommandQueueID();7290}72917292// Delete the driver once everything else has been deleted.7293if (driver != nullptr) {7294context->driver_free(driver);7295driver = nullptr;7296}72977298// All these should be clear at this point.7299ERR_FAIL_COND(dependency_map.size());7300ERR_FAIL_COND(reverse_dependency_map.size());7301}73027303void RenderingDevice::_set_max_fps(int p_max_fps) {7304for (const KeyValue<DisplayServer::WindowID, RDD::SwapChainID> &it : screen_swap_chains) {7305driver->swap_chain_set_max_fps(it.value, p_max_fps);7306}7307}73087309RenderingDevice *RenderingDevice::create_local_device() {7310RenderingDevice *rd = memnew(RenderingDevice);7311if (rd->initialize(context) != OK) {7312memdelete(rd);7313return nullptr;7314}7315return rd;7316}73177318bool RenderingDevice::has_feature(const Features p_feature) const {7319// Some features can be deduced from the capabilities without querying the driver and looking at the capabilities.7320switch (p_feature) {7321case SUPPORTS_MULTIVIEW: {7322const RDD::MultiviewCapabilities &multiview_capabilities = driver->get_multiview_capabilities();7323return multiview_capabilities.is_supported && multiview_capabilities.max_view_count > 1;7324}7325case SUPPORTS_ATTACHMENT_VRS: {7326const RDD::FragmentShadingRateCapabilities &fsr_capabilities = driver->get_fragment_shading_rate_capabilities();7327const RDD::FragmentDensityMapCapabilities &fdm_capabilities = driver->get_fragment_density_map_capabilities();7328return fsr_capabilities.attachment_supported || fdm_capabilities.attachment_supported;7329}7330default:7331return driver->has_feature(p_feature);7332}7333}73347335void RenderingDevice::_bind_methods() {7336ClassDB::bind_method(D_METHOD("texture_create", "format", "view", "data"), &RenderingDevice::_texture_create, DEFVAL(Array()));7337ClassDB::bind_method(D_METHOD("texture_create_shared", "view", "with_texture"), &RenderingDevice::_texture_create_shared);7338ClassDB::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));7339ClassDB::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));73407341ClassDB::bind_method(D_METHOD("texture_update", "texture", "layer", "data"), &RenderingDevice::texture_update);7342ClassDB::bind_method(D_METHOD("texture_get_data", "texture", "layer"), &RenderingDevice::texture_get_data);7343ClassDB::bind_method(D_METHOD("texture_get_data_async", "texture", "layer", "callback"), &RenderingDevice::texture_get_data_async);73447345ClassDB::bind_method(D_METHOD("texture_is_format_supported_for_usage", "format", "usage_flags"), &RenderingDevice::texture_is_format_supported_for_usage);73467347ClassDB::bind_method(D_METHOD("texture_is_shared", "texture"), &RenderingDevice::texture_is_shared);7348ClassDB::bind_method(D_METHOD("texture_is_valid", "texture"), &RenderingDevice::texture_is_valid);73497350ClassDB::bind_method(D_METHOD("texture_set_discardable", "texture", "discardable"), &RenderingDevice::texture_set_discardable);7351ClassDB::bind_method(D_METHOD("texture_is_discardable", "texture"), &RenderingDevice::texture_is_discardable);73527353ClassDB::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);7354ClassDB::bind_method(D_METHOD("texture_clear", "texture", "color", "base_mipmap", "mipmap_count", "base_layer", "layer_count"), &RenderingDevice::texture_clear);7355ClassDB::bind_method(D_METHOD("texture_resolve_multisample", "from_texture", "to_texture"), &RenderingDevice::texture_resolve_multisample);73567357ClassDB::bind_method(D_METHOD("texture_get_format", "texture"), &RenderingDevice::_texture_get_format);7358#ifndef DISABLE_DEPRECATED7359ClassDB::bind_method(D_METHOD("texture_get_native_handle", "texture"), &RenderingDevice::texture_get_native_handle);7360#endif73617362ClassDB::bind_method(D_METHOD("framebuffer_format_create", "attachments", "view_count"), &RenderingDevice::_framebuffer_format_create, DEFVAL(1));7363ClassDB::bind_method(D_METHOD("framebuffer_format_create_multipass", "attachments", "passes", "view_count"), &RenderingDevice::_framebuffer_format_create_multipass, DEFVAL(1));7364ClassDB::bind_method(D_METHOD("framebuffer_format_create_empty", "samples"), &RenderingDevice::framebuffer_format_create_empty, DEFVAL(TEXTURE_SAMPLES_1));7365ClassDB::bind_method(D_METHOD("framebuffer_format_get_texture_samples", "format", "render_pass"), &RenderingDevice::framebuffer_format_get_texture_samples, DEFVAL(0));7366ClassDB::bind_method(D_METHOD("framebuffer_create", "textures", "validate_with_format", "view_count"), &RenderingDevice::_framebuffer_create, DEFVAL(INVALID_FORMAT_ID), DEFVAL(1));7367ClassDB::bind_method(D_METHOD("framebuffer_create_multipass", "textures", "passes", "validate_with_format", "view_count"), &RenderingDevice::_framebuffer_create_multipass, DEFVAL(INVALID_FORMAT_ID), DEFVAL(1));7368ClassDB::bind_method(D_METHOD("framebuffer_create_empty", "size", "samples", "validate_with_format"), &RenderingDevice::framebuffer_create_empty, DEFVAL(TEXTURE_SAMPLES_1), DEFVAL(INVALID_FORMAT_ID));7369ClassDB::bind_method(D_METHOD("framebuffer_get_format", "framebuffer"), &RenderingDevice::framebuffer_get_format);7370ClassDB::bind_method(D_METHOD("framebuffer_is_valid", "framebuffer"), &RenderingDevice::framebuffer_is_valid);73717372ClassDB::bind_method(D_METHOD("sampler_create", "state"), &RenderingDevice::_sampler_create);7373ClassDB::bind_method(D_METHOD("sampler_is_format_supported_for_filter", "format", "sampler_filter"), &RenderingDevice::sampler_is_format_supported_for_filter);73747375ClassDB::bind_method(D_METHOD("vertex_buffer_create", "size_bytes", "data", "creation_bits"), &RenderingDevice::_vertex_buffer_create, DEFVAL(Vector<uint8_t>()), DEFVAL(0));7376ClassDB::bind_method(D_METHOD("vertex_format_create", "vertex_descriptions"), &RenderingDevice::_vertex_format_create);7377ClassDB::bind_method(D_METHOD("vertex_array_create", "vertex_count", "vertex_format", "src_buffers", "offsets"), &RenderingDevice::_vertex_array_create, DEFVAL(Vector<int64_t>()));73787379ClassDB::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));7380ClassDB::bind_method(D_METHOD("index_array_create", "index_buffer", "index_offset", "index_count"), &RenderingDevice::index_array_create);73817382ClassDB::bind_method(D_METHOD("shader_compile_spirv_from_source", "shader_source", "allow_cache"), &RenderingDevice::_shader_compile_spirv_from_source, DEFVAL(true));7383ClassDB::bind_method(D_METHOD("shader_compile_binary_from_spirv", "spirv_data", "name"), &RenderingDevice::_shader_compile_binary_from_spirv, DEFVAL(""));7384ClassDB::bind_method(D_METHOD("shader_create_from_spirv", "spirv_data", "name"), &RenderingDevice::_shader_create_from_spirv, DEFVAL(""));7385ClassDB::bind_method(D_METHOD("shader_create_from_bytecode", "binary_data", "placeholder_rid"), &RenderingDevice::shader_create_from_bytecode, DEFVAL(RID()));7386ClassDB::bind_method(D_METHOD("shader_create_placeholder"), &RenderingDevice::shader_create_placeholder);73877388ClassDB::bind_method(D_METHOD("shader_get_vertex_input_attribute_mask", "shader"), &RenderingDevice::shader_get_vertex_input_attribute_mask);73897390ClassDB::bind_method(D_METHOD("uniform_buffer_create", "size_bytes", "data", "creation_bits"), &RenderingDevice::_uniform_buffer_create, DEFVAL(Vector<uint8_t>()), DEFVAL(0));7391ClassDB::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));7392ClassDB::bind_method(D_METHOD("texture_buffer_create", "size_bytes", "format", "data"), &RenderingDevice::_texture_buffer_create, DEFVAL(Vector<uint8_t>()));73937394ClassDB::bind_method(D_METHOD("uniform_set_create", "uniforms", "shader", "shader_set"), &RenderingDevice::_uniform_set_create);7395ClassDB::bind_method(D_METHOD("uniform_set_is_valid", "uniform_set"), &RenderingDevice::uniform_set_is_valid);73967397ClassDB::bind_method(D_METHOD("buffer_copy", "src_buffer", "dst_buffer", "src_offset", "dst_offset", "size"), &RenderingDevice::buffer_copy);7398ClassDB::bind_method(D_METHOD("buffer_update", "buffer", "offset", "size_bytes", "data"), &RenderingDevice::_buffer_update_bind);7399ClassDB::bind_method(D_METHOD("buffer_clear", "buffer", "offset", "size_bytes"), &RenderingDevice::buffer_clear);7400ClassDB::bind_method(D_METHOD("buffer_get_data", "buffer", "offset_bytes", "size_bytes"), &RenderingDevice::buffer_get_data, DEFVAL(0), DEFVAL(0));7401ClassDB::bind_method(D_METHOD("buffer_get_data_async", "buffer", "callback", "offset_bytes", "size_bytes"), &RenderingDevice::buffer_get_data_async, DEFVAL(0), DEFVAL(0));7402ClassDB::bind_method(D_METHOD("buffer_get_device_address", "buffer"), &RenderingDevice::buffer_get_device_address);74037404ClassDB::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>()));7405ClassDB::bind_method(D_METHOD("render_pipeline_is_valid", "render_pipeline"), &RenderingDevice::render_pipeline_is_valid);74067407ClassDB::bind_method(D_METHOD("compute_pipeline_create", "shader", "specialization_constants"), &RenderingDevice::_compute_pipeline_create, DEFVAL(TypedArray<RDPipelineSpecializationConstant>()));7408ClassDB::bind_method(D_METHOD("compute_pipeline_is_valid", "compute_pipeline"), &RenderingDevice::compute_pipeline_is_valid);74097410ClassDB::bind_method(D_METHOD("screen_get_width", "screen"), &RenderingDevice::screen_get_width, DEFVAL(DisplayServer::MAIN_WINDOW_ID));7411ClassDB::bind_method(D_METHOD("screen_get_height", "screen"), &RenderingDevice::screen_get_height, DEFVAL(DisplayServer::MAIN_WINDOW_ID));7412ClassDB::bind_method(D_METHOD("screen_get_framebuffer_format", "screen"), &RenderingDevice::screen_get_framebuffer_format, DEFVAL(DisplayServer::MAIN_WINDOW_ID));74137414ClassDB::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()));74157416ClassDB::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));7417#ifndef DISABLE_DEPRECATED7418ClassDB::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>()));7419#endif74207421ClassDB::bind_method(D_METHOD("draw_list_set_blend_constants", "draw_list", "color"), &RenderingDevice::draw_list_set_blend_constants);7422ClassDB::bind_method(D_METHOD("draw_list_bind_render_pipeline", "draw_list", "render_pipeline"), &RenderingDevice::draw_list_bind_render_pipeline);7423ClassDB::bind_method(D_METHOD("draw_list_bind_uniform_set", "draw_list", "uniform_set", "set_index"), &RenderingDevice::draw_list_bind_uniform_set);7424ClassDB::bind_method(D_METHOD("draw_list_bind_vertex_array", "draw_list", "vertex_array"), &RenderingDevice::draw_list_bind_vertex_array);7425ClassDB::bind_method(D_METHOD("draw_list_bind_index_array", "draw_list", "index_array"), &RenderingDevice::draw_list_bind_index_array);7426ClassDB::bind_method(D_METHOD("draw_list_set_push_constant", "draw_list", "buffer", "size_bytes"), &RenderingDevice::_draw_list_set_push_constant);74277428ClassDB::bind_method(D_METHOD("draw_list_draw", "draw_list", "use_indices", "instances", "procedural_vertex_count"), &RenderingDevice::draw_list_draw, DEFVAL(0));7429ClassDB::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));74307431ClassDB::bind_method(D_METHOD("draw_list_enable_scissor", "draw_list", "rect"), &RenderingDevice::draw_list_enable_scissor, DEFVAL(Rect2()));7432ClassDB::bind_method(D_METHOD("draw_list_disable_scissor", "draw_list"), &RenderingDevice::draw_list_disable_scissor);74337434ClassDB::bind_method(D_METHOD("draw_list_switch_to_next_pass"), &RenderingDevice::draw_list_switch_to_next_pass);7435#ifndef DISABLE_DEPRECATED7436ClassDB::bind_method(D_METHOD("draw_list_switch_to_next_pass_split", "splits"), &RenderingDevice::_draw_list_switch_to_next_pass_split);7437#endif74387439ClassDB::bind_method(D_METHOD("draw_list_end"), &RenderingDevice::draw_list_end);74407441ClassDB::bind_method(D_METHOD("compute_list_begin"), &RenderingDevice::compute_list_begin);7442ClassDB::bind_method(D_METHOD("compute_list_bind_compute_pipeline", "compute_list", "compute_pipeline"), &RenderingDevice::compute_list_bind_compute_pipeline);7443ClassDB::bind_method(D_METHOD("compute_list_set_push_constant", "compute_list", "buffer", "size_bytes"), &RenderingDevice::_compute_list_set_push_constant);7444ClassDB::bind_method(D_METHOD("compute_list_bind_uniform_set", "compute_list", "uniform_set", "set_index"), &RenderingDevice::compute_list_bind_uniform_set);7445ClassDB::bind_method(D_METHOD("compute_list_dispatch", "compute_list", "x_groups", "y_groups", "z_groups"), &RenderingDevice::compute_list_dispatch);7446ClassDB::bind_method(D_METHOD("compute_list_dispatch_indirect", "compute_list", "buffer", "offset"), &RenderingDevice::compute_list_dispatch_indirect);7447ClassDB::bind_method(D_METHOD("compute_list_add_barrier", "compute_list"), &RenderingDevice::compute_list_add_barrier);7448ClassDB::bind_method(D_METHOD("compute_list_end"), &RenderingDevice::compute_list_end);74497450ClassDB::bind_method(D_METHOD("free_rid", "rid"), &RenderingDevice::free_rid);74517452ClassDB::bind_method(D_METHOD("capture_timestamp", "name"), &RenderingDevice::capture_timestamp);7453ClassDB::bind_method(D_METHOD("get_captured_timestamps_count"), &RenderingDevice::get_captured_timestamps_count);7454ClassDB::bind_method(D_METHOD("get_captured_timestamps_frame"), &RenderingDevice::get_captured_timestamps_frame);7455ClassDB::bind_method(D_METHOD("get_captured_timestamp_gpu_time", "index"), &RenderingDevice::get_captured_timestamp_gpu_time);7456ClassDB::bind_method(D_METHOD("get_captured_timestamp_cpu_time", "index"), &RenderingDevice::get_captured_timestamp_cpu_time);7457ClassDB::bind_method(D_METHOD("get_captured_timestamp_name", "index"), &RenderingDevice::get_captured_timestamp_name);74587459ClassDB::bind_method(D_METHOD("has_feature", "feature"), &RenderingDevice::has_feature);7460ClassDB::bind_method(D_METHOD("limit_get", "limit"), &RenderingDevice::limit_get);7461ClassDB::bind_method(D_METHOD("get_frame_delay"), &RenderingDevice::get_frame_delay);7462ClassDB::bind_method(D_METHOD("submit"), &RenderingDevice::submit);7463ClassDB::bind_method(D_METHOD("sync"), &RenderingDevice::sync);74647465#ifndef DISABLE_DEPRECATED7466ClassDB::bind_method(D_METHOD("barrier", "from", "to"), &RenderingDevice::barrier, DEFVAL(BARRIER_MASK_ALL_BARRIERS), DEFVAL(BARRIER_MASK_ALL_BARRIERS));7467ClassDB::bind_method(D_METHOD("full_barrier"), &RenderingDevice::full_barrier);7468#endif74697470ClassDB::bind_method(D_METHOD("create_local_device"), &RenderingDevice::create_local_device);74717472ClassDB::bind_method(D_METHOD("set_resource_name", "id", "name"), &RenderingDevice::set_resource_name);74737474ClassDB::bind_method(D_METHOD("draw_command_begin_label", "name", "color"), &RenderingDevice::_draw_command_begin_label);7475#ifndef DISABLE_DEPRECATED7476ClassDB::bind_method(D_METHOD("draw_command_insert_label", "name", "color"), &RenderingDevice::draw_command_insert_label);7477#endif7478ClassDB::bind_method(D_METHOD("draw_command_end_label"), &RenderingDevice::draw_command_end_label);74797480ClassDB::bind_method(D_METHOD("get_device_vendor_name"), &RenderingDevice::get_device_vendor_name);7481ClassDB::bind_method(D_METHOD("get_device_name"), &RenderingDevice::get_device_name);7482ClassDB::bind_method(D_METHOD("get_device_pipeline_cache_uuid"), &RenderingDevice::get_device_pipeline_cache_uuid);74837484ClassDB::bind_method(D_METHOD("get_memory_usage", "type"), &RenderingDevice::get_memory_usage);74857486ClassDB::bind_method(D_METHOD("get_driver_resource", "resource", "rid", "index"), &RenderingDevice::get_driver_resource);74877488ClassDB::bind_method(D_METHOD("get_perf_report"), &RenderingDevice::get_perf_report);74897490ClassDB::bind_method(D_METHOD("get_driver_and_device_memory_report"), &RenderingDevice::get_driver_and_device_memory_report);7491ClassDB::bind_method(D_METHOD("get_tracked_object_name", "type_index"), &RenderingDevice::get_tracked_object_name);7492ClassDB::bind_method(D_METHOD("get_tracked_object_type_count"), &RenderingDevice::get_tracked_object_type_count);7493ClassDB::bind_method(D_METHOD("get_driver_total_memory"), &RenderingDevice::get_driver_total_memory);7494ClassDB::bind_method(D_METHOD("get_driver_allocation_count"), &RenderingDevice::get_driver_allocation_count);7495ClassDB::bind_method(D_METHOD("get_driver_memory_by_object_type", "type"), &RenderingDevice::get_driver_memory_by_object_type);7496ClassDB::bind_method(D_METHOD("get_driver_allocs_by_object_type", "type"), &RenderingDevice::get_driver_allocs_by_object_type);7497ClassDB::bind_method(D_METHOD("get_device_total_memory"), &RenderingDevice::get_device_total_memory);7498ClassDB::bind_method(D_METHOD("get_device_allocation_count"), &RenderingDevice::get_device_allocation_count);7499ClassDB::bind_method(D_METHOD("get_device_memory_by_object_type", "type"), &RenderingDevice::get_device_memory_by_object_type);7500ClassDB::bind_method(D_METHOD("get_device_allocs_by_object_type", "type"), &RenderingDevice::get_device_allocs_by_object_type);75017502BIND_ENUM_CONSTANT(DEVICE_TYPE_OTHER);7503BIND_ENUM_CONSTANT(DEVICE_TYPE_INTEGRATED_GPU);7504BIND_ENUM_CONSTANT(DEVICE_TYPE_DISCRETE_GPU);7505BIND_ENUM_CONSTANT(DEVICE_TYPE_VIRTUAL_GPU);7506BIND_ENUM_CONSTANT(DEVICE_TYPE_CPU);7507BIND_ENUM_CONSTANT(DEVICE_TYPE_MAX);75087509BIND_ENUM_CONSTANT(DRIVER_RESOURCE_LOGICAL_DEVICE);7510BIND_ENUM_CONSTANT(DRIVER_RESOURCE_PHYSICAL_DEVICE);7511BIND_ENUM_CONSTANT(DRIVER_RESOURCE_TOPMOST_OBJECT);7512BIND_ENUM_CONSTANT(DRIVER_RESOURCE_COMMAND_QUEUE);7513BIND_ENUM_CONSTANT(DRIVER_RESOURCE_QUEUE_FAMILY);7514BIND_ENUM_CONSTANT(DRIVER_RESOURCE_TEXTURE);7515BIND_ENUM_CONSTANT(DRIVER_RESOURCE_TEXTURE_VIEW);7516BIND_ENUM_CONSTANT(DRIVER_RESOURCE_TEXTURE_DATA_FORMAT);7517BIND_ENUM_CONSTANT(DRIVER_RESOURCE_SAMPLER);7518BIND_ENUM_CONSTANT(DRIVER_RESOURCE_UNIFORM_SET);7519BIND_ENUM_CONSTANT(DRIVER_RESOURCE_BUFFER);7520BIND_ENUM_CONSTANT(DRIVER_RESOURCE_COMPUTE_PIPELINE);7521BIND_ENUM_CONSTANT(DRIVER_RESOURCE_RENDER_PIPELINE);7522#ifndef DISABLE_DEPRECATED7523BIND_ENUM_CONSTANT(DRIVER_RESOURCE_VULKAN_DEVICE);7524BIND_ENUM_CONSTANT(DRIVER_RESOURCE_VULKAN_PHYSICAL_DEVICE);7525BIND_ENUM_CONSTANT(DRIVER_RESOURCE_VULKAN_INSTANCE);7526BIND_ENUM_CONSTANT(DRIVER_RESOURCE_VULKAN_QUEUE);7527BIND_ENUM_CONSTANT(DRIVER_RESOURCE_VULKAN_QUEUE_FAMILY_INDEX);7528BIND_ENUM_CONSTANT(DRIVER_RESOURCE_VULKAN_IMAGE);7529BIND_ENUM_CONSTANT(DRIVER_RESOURCE_VULKAN_IMAGE_VIEW);7530BIND_ENUM_CONSTANT(DRIVER_RESOURCE_VULKAN_IMAGE_NATIVE_TEXTURE_FORMAT);7531BIND_ENUM_CONSTANT(DRIVER_RESOURCE_VULKAN_SAMPLER);7532BIND_ENUM_CONSTANT(DRIVER_RESOURCE_VULKAN_DESCRIPTOR_SET);7533BIND_ENUM_CONSTANT(DRIVER_RESOURCE_VULKAN_BUFFER);7534BIND_ENUM_CONSTANT(DRIVER_RESOURCE_VULKAN_COMPUTE_PIPELINE);7535BIND_ENUM_CONSTANT(DRIVER_RESOURCE_VULKAN_RENDER_PIPELINE);7536#endif75377538BIND_ENUM_CONSTANT(DATA_FORMAT_R4G4_UNORM_PACK8);7539BIND_ENUM_CONSTANT(DATA_FORMAT_R4G4B4A4_UNORM_PACK16);7540BIND_ENUM_CONSTANT(DATA_FORMAT_B4G4R4A4_UNORM_PACK16);7541BIND_ENUM_CONSTANT(DATA_FORMAT_R5G6B5_UNORM_PACK16);7542BIND_ENUM_CONSTANT(DATA_FORMAT_B5G6R5_UNORM_PACK16);7543BIND_ENUM_CONSTANT(DATA_FORMAT_R5G5B5A1_UNORM_PACK16);7544BIND_ENUM_CONSTANT(DATA_FORMAT_B5G5R5A1_UNORM_PACK16);7545BIND_ENUM_CONSTANT(DATA_FORMAT_A1R5G5B5_UNORM_PACK16);7546BIND_ENUM_CONSTANT(DATA_FORMAT_R8_UNORM);7547BIND_ENUM_CONSTANT(DATA_FORMAT_R8_SNORM);7548BIND_ENUM_CONSTANT(DATA_FORMAT_R8_USCALED);7549BIND_ENUM_CONSTANT(DATA_FORMAT_R8_SSCALED);7550BIND_ENUM_CONSTANT(DATA_FORMAT_R8_UINT);7551BIND_ENUM_CONSTANT(DATA_FORMAT_R8_SINT);7552BIND_ENUM_CONSTANT(DATA_FORMAT_R8_SRGB);7553BIND_ENUM_CONSTANT(DATA_FORMAT_R8G8_UNORM);7554BIND_ENUM_CONSTANT(DATA_FORMAT_R8G8_SNORM);7555BIND_ENUM_CONSTANT(DATA_FORMAT_R8G8_USCALED);7556BIND_ENUM_CONSTANT(DATA_FORMAT_R8G8_SSCALED);7557BIND_ENUM_CONSTANT(DATA_FORMAT_R8G8_UINT);7558BIND_ENUM_CONSTANT(DATA_FORMAT_R8G8_SINT);7559BIND_ENUM_CONSTANT(DATA_FORMAT_R8G8_SRGB);7560BIND_ENUM_CONSTANT(DATA_FORMAT_R8G8B8_UNORM);7561BIND_ENUM_CONSTANT(DATA_FORMAT_R8G8B8_SNORM);7562BIND_ENUM_CONSTANT(DATA_FORMAT_R8G8B8_USCALED);7563BIND_ENUM_CONSTANT(DATA_FORMAT_R8G8B8_SSCALED);7564BIND_ENUM_CONSTANT(DATA_FORMAT_R8G8B8_UINT);7565BIND_ENUM_CONSTANT(DATA_FORMAT_R8G8B8_SINT);7566BIND_ENUM_CONSTANT(DATA_FORMAT_R8G8B8_SRGB);7567BIND_ENUM_CONSTANT(DATA_FORMAT_B8G8R8_UNORM);7568BIND_ENUM_CONSTANT(DATA_FORMAT_B8G8R8_SNORM);7569BIND_ENUM_CONSTANT(DATA_FORMAT_B8G8R8_USCALED);7570BIND_ENUM_CONSTANT(DATA_FORMAT_B8G8R8_SSCALED);7571BIND_ENUM_CONSTANT(DATA_FORMAT_B8G8R8_UINT);7572BIND_ENUM_CONSTANT(DATA_FORMAT_B8G8R8_SINT);7573BIND_ENUM_CONSTANT(DATA_FORMAT_B8G8R8_SRGB);7574BIND_ENUM_CONSTANT(DATA_FORMAT_R8G8B8A8_UNORM);7575BIND_ENUM_CONSTANT(DATA_FORMAT_R8G8B8A8_SNORM);7576BIND_ENUM_CONSTANT(DATA_FORMAT_R8G8B8A8_USCALED);7577BIND_ENUM_CONSTANT(DATA_FORMAT_R8G8B8A8_SSCALED);7578BIND_ENUM_CONSTANT(DATA_FORMAT_R8G8B8A8_UINT);7579BIND_ENUM_CONSTANT(DATA_FORMAT_R8G8B8A8_SINT);7580BIND_ENUM_CONSTANT(DATA_FORMAT_R8G8B8A8_SRGB);7581BIND_ENUM_CONSTANT(DATA_FORMAT_B8G8R8A8_UNORM);7582BIND_ENUM_CONSTANT(DATA_FORMAT_B8G8R8A8_SNORM);7583BIND_ENUM_CONSTANT(DATA_FORMAT_B8G8R8A8_USCALED);7584BIND_ENUM_CONSTANT(DATA_FORMAT_B8G8R8A8_SSCALED);7585BIND_ENUM_CONSTANT(DATA_FORMAT_B8G8R8A8_UINT);7586BIND_ENUM_CONSTANT(DATA_FORMAT_B8G8R8A8_SINT);7587BIND_ENUM_CONSTANT(DATA_FORMAT_B8G8R8A8_SRGB);7588BIND_ENUM_CONSTANT(DATA_FORMAT_A8B8G8R8_UNORM_PACK32);7589BIND_ENUM_CONSTANT(DATA_FORMAT_A8B8G8R8_SNORM_PACK32);7590BIND_ENUM_CONSTANT(DATA_FORMAT_A8B8G8R8_USCALED_PACK32);7591BIND_ENUM_CONSTANT(DATA_FORMAT_A8B8G8R8_SSCALED_PACK32);7592BIND_ENUM_CONSTANT(DATA_FORMAT_A8B8G8R8_UINT_PACK32);7593BIND_ENUM_CONSTANT(DATA_FORMAT_A8B8G8R8_SINT_PACK32);7594BIND_ENUM_CONSTANT(DATA_FORMAT_A8B8G8R8_SRGB_PACK32);7595BIND_ENUM_CONSTANT(DATA_FORMAT_A2R10G10B10_UNORM_PACK32);7596BIND_ENUM_CONSTANT(DATA_FORMAT_A2R10G10B10_SNORM_PACK32);7597BIND_ENUM_CONSTANT(DATA_FORMAT_A2R10G10B10_USCALED_PACK32);7598BIND_ENUM_CONSTANT(DATA_FORMAT_A2R10G10B10_SSCALED_PACK32);7599BIND_ENUM_CONSTANT(DATA_FORMAT_A2R10G10B10_UINT_PACK32);7600BIND_ENUM_CONSTANT(DATA_FORMAT_A2R10G10B10_SINT_PACK32);7601BIND_ENUM_CONSTANT(DATA_FORMAT_A2B10G10R10_UNORM_PACK32);7602BIND_ENUM_CONSTANT(DATA_FORMAT_A2B10G10R10_SNORM_PACK32);7603BIND_ENUM_CONSTANT(DATA_FORMAT_A2B10G10R10_USCALED_PACK32);7604BIND_ENUM_CONSTANT(DATA_FORMAT_A2B10G10R10_SSCALED_PACK32);7605BIND_ENUM_CONSTANT(DATA_FORMAT_A2B10G10R10_UINT_PACK32);7606BIND_ENUM_CONSTANT(DATA_FORMAT_A2B10G10R10_SINT_PACK32);7607BIND_ENUM_CONSTANT(DATA_FORMAT_R16_UNORM);7608BIND_ENUM_CONSTANT(DATA_FORMAT_R16_SNORM);7609BIND_ENUM_CONSTANT(DATA_FORMAT_R16_USCALED);7610BIND_ENUM_CONSTANT(DATA_FORMAT_R16_SSCALED);7611BIND_ENUM_CONSTANT(DATA_FORMAT_R16_UINT);7612BIND_ENUM_CONSTANT(DATA_FORMAT_R16_SINT);7613BIND_ENUM_CONSTANT(DATA_FORMAT_R16_SFLOAT);7614BIND_ENUM_CONSTANT(DATA_FORMAT_R16G16_UNORM);7615BIND_ENUM_CONSTANT(DATA_FORMAT_R16G16_SNORM);7616BIND_ENUM_CONSTANT(DATA_FORMAT_R16G16_USCALED);7617BIND_ENUM_CONSTANT(DATA_FORMAT_R16G16_SSCALED);7618BIND_ENUM_CONSTANT(DATA_FORMAT_R16G16_UINT);7619BIND_ENUM_CONSTANT(DATA_FORMAT_R16G16_SINT);7620BIND_ENUM_CONSTANT(DATA_FORMAT_R16G16_SFLOAT);7621BIND_ENUM_CONSTANT(DATA_FORMAT_R16G16B16_UNORM);7622BIND_ENUM_CONSTANT(DATA_FORMAT_R16G16B16_SNORM);7623BIND_ENUM_CONSTANT(DATA_FORMAT_R16G16B16_USCALED);7624BIND_ENUM_CONSTANT(DATA_FORMAT_R16G16B16_SSCALED);7625BIND_ENUM_CONSTANT(DATA_FORMAT_R16G16B16_UINT);7626BIND_ENUM_CONSTANT(DATA_FORMAT_R16G16B16_SINT);7627BIND_ENUM_CONSTANT(DATA_FORMAT_R16G16B16_SFLOAT);7628BIND_ENUM_CONSTANT(DATA_FORMAT_R16G16B16A16_UNORM);7629BIND_ENUM_CONSTANT(DATA_FORMAT_R16G16B16A16_SNORM);7630BIND_ENUM_CONSTANT(DATA_FORMAT_R16G16B16A16_USCALED);7631BIND_ENUM_CONSTANT(DATA_FORMAT_R16G16B16A16_SSCALED);7632BIND_ENUM_CONSTANT(DATA_FORMAT_R16G16B16A16_UINT);7633BIND_ENUM_CONSTANT(DATA_FORMAT_R16G16B16A16_SINT);7634BIND_ENUM_CONSTANT(DATA_FORMAT_R16G16B16A16_SFLOAT);7635BIND_ENUM_CONSTANT(DATA_FORMAT_R32_UINT);7636BIND_ENUM_CONSTANT(DATA_FORMAT_R32_SINT);7637BIND_ENUM_CONSTANT(DATA_FORMAT_R32_SFLOAT);7638BIND_ENUM_CONSTANT(DATA_FORMAT_R32G32_UINT);7639BIND_ENUM_CONSTANT(DATA_FORMAT_R32G32_SINT);7640BIND_ENUM_CONSTANT(DATA_FORMAT_R32G32_SFLOAT);7641BIND_ENUM_CONSTANT(DATA_FORMAT_R32G32B32_UINT);7642BIND_ENUM_CONSTANT(DATA_FORMAT_R32G32B32_SINT);7643BIND_ENUM_CONSTANT(DATA_FORMAT_R32G32B32_SFLOAT);7644BIND_ENUM_CONSTANT(DATA_FORMAT_R32G32B32A32_UINT);7645BIND_ENUM_CONSTANT(DATA_FORMAT_R32G32B32A32_SINT);7646BIND_ENUM_CONSTANT(DATA_FORMAT_R32G32B32A32_SFLOAT);7647BIND_ENUM_CONSTANT(DATA_FORMAT_R64_UINT);7648BIND_ENUM_CONSTANT(DATA_FORMAT_R64_SINT);7649BIND_ENUM_CONSTANT(DATA_FORMAT_R64_SFLOAT);7650BIND_ENUM_CONSTANT(DATA_FORMAT_R64G64_UINT);7651BIND_ENUM_CONSTANT(DATA_FORMAT_R64G64_SINT);7652BIND_ENUM_CONSTANT(DATA_FORMAT_R64G64_SFLOAT);7653BIND_ENUM_CONSTANT(DATA_FORMAT_R64G64B64_UINT);7654BIND_ENUM_CONSTANT(DATA_FORMAT_R64G64B64_SINT);7655BIND_ENUM_CONSTANT(DATA_FORMAT_R64G64B64_SFLOAT);7656BIND_ENUM_CONSTANT(DATA_FORMAT_R64G64B64A64_UINT);7657BIND_ENUM_CONSTANT(DATA_FORMAT_R64G64B64A64_SINT);7658BIND_ENUM_CONSTANT(DATA_FORMAT_R64G64B64A64_SFLOAT);7659BIND_ENUM_CONSTANT(DATA_FORMAT_B10G11R11_UFLOAT_PACK32);7660BIND_ENUM_CONSTANT(DATA_FORMAT_E5B9G9R9_UFLOAT_PACK32);7661BIND_ENUM_CONSTANT(DATA_FORMAT_D16_UNORM);7662BIND_ENUM_CONSTANT(DATA_FORMAT_X8_D24_UNORM_PACK32);7663BIND_ENUM_CONSTANT(DATA_FORMAT_D32_SFLOAT);7664BIND_ENUM_CONSTANT(DATA_FORMAT_S8_UINT);7665BIND_ENUM_CONSTANT(DATA_FORMAT_D16_UNORM_S8_UINT);7666BIND_ENUM_CONSTANT(DATA_FORMAT_D24_UNORM_S8_UINT);7667BIND_ENUM_CONSTANT(DATA_FORMAT_D32_SFLOAT_S8_UINT);7668BIND_ENUM_CONSTANT(DATA_FORMAT_BC1_RGB_UNORM_BLOCK);7669BIND_ENUM_CONSTANT(DATA_FORMAT_BC1_RGB_SRGB_BLOCK);7670BIND_ENUM_CONSTANT(DATA_FORMAT_BC1_RGBA_UNORM_BLOCK);7671BIND_ENUM_CONSTANT(DATA_FORMAT_BC1_RGBA_SRGB_BLOCK);7672BIND_ENUM_CONSTANT(DATA_FORMAT_BC2_UNORM_BLOCK);7673BIND_ENUM_CONSTANT(DATA_FORMAT_BC2_SRGB_BLOCK);7674BIND_ENUM_CONSTANT(DATA_FORMAT_BC3_UNORM_BLOCK);7675BIND_ENUM_CONSTANT(DATA_FORMAT_BC3_SRGB_BLOCK);7676BIND_ENUM_CONSTANT(DATA_FORMAT_BC4_UNORM_BLOCK);7677BIND_ENUM_CONSTANT(DATA_FORMAT_BC4_SNORM_BLOCK);7678BIND_ENUM_CONSTANT(DATA_FORMAT_BC5_UNORM_BLOCK);7679BIND_ENUM_CONSTANT(DATA_FORMAT_BC5_SNORM_BLOCK);7680BIND_ENUM_CONSTANT(DATA_FORMAT_BC6H_UFLOAT_BLOCK);7681BIND_ENUM_CONSTANT(DATA_FORMAT_BC6H_SFLOAT_BLOCK);7682BIND_ENUM_CONSTANT(DATA_FORMAT_BC7_UNORM_BLOCK);7683BIND_ENUM_CONSTANT(DATA_FORMAT_BC7_SRGB_BLOCK);7684BIND_ENUM_CONSTANT(DATA_FORMAT_ETC2_R8G8B8_UNORM_BLOCK);7685BIND_ENUM_CONSTANT(DATA_FORMAT_ETC2_R8G8B8_SRGB_BLOCK);7686BIND_ENUM_CONSTANT(DATA_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK);7687BIND_ENUM_CONSTANT(DATA_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK);7688BIND_ENUM_CONSTANT(DATA_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK);7689BIND_ENUM_CONSTANT(DATA_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK);7690BIND_ENUM_CONSTANT(DATA_FORMAT_EAC_R11_UNORM_BLOCK);7691BIND_ENUM_CONSTANT(DATA_FORMAT_EAC_R11_SNORM_BLOCK);7692BIND_ENUM_CONSTANT(DATA_FORMAT_EAC_R11G11_UNORM_BLOCK);7693BIND_ENUM_CONSTANT(DATA_FORMAT_EAC_R11G11_SNORM_BLOCK);7694BIND_ENUM_CONSTANT(DATA_FORMAT_ASTC_4x4_UNORM_BLOCK);7695BIND_ENUM_CONSTANT(DATA_FORMAT_ASTC_4x4_SRGB_BLOCK);7696BIND_ENUM_CONSTANT(DATA_FORMAT_ASTC_5x4_UNORM_BLOCK);7697BIND_ENUM_CONSTANT(DATA_FORMAT_ASTC_5x4_SRGB_BLOCK);7698BIND_ENUM_CONSTANT(DATA_FORMAT_ASTC_5x5_UNORM_BLOCK);7699BIND_ENUM_CONSTANT(DATA_FORMAT_ASTC_5x5_SRGB_BLOCK);7700BIND_ENUM_CONSTANT(DATA_FORMAT_ASTC_6x5_UNORM_BLOCK);7701BIND_ENUM_CONSTANT(DATA_FORMAT_ASTC_6x5_SRGB_BLOCK);7702BIND_ENUM_CONSTANT(DATA_FORMAT_ASTC_6x6_UNORM_BLOCK);7703BIND_ENUM_CONSTANT(DATA_FORMAT_ASTC_6x6_SRGB_BLOCK);7704BIND_ENUM_CONSTANT(DATA_FORMAT_ASTC_8x5_UNORM_BLOCK);7705BIND_ENUM_CONSTANT(DATA_FORMAT_ASTC_8x5_SRGB_BLOCK);7706BIND_ENUM_CONSTANT(DATA_FORMAT_ASTC_8x6_UNORM_BLOCK);7707BIND_ENUM_CONSTANT(DATA_FORMAT_ASTC_8x6_SRGB_BLOCK);7708BIND_ENUM_CONSTANT(DATA_FORMAT_ASTC_8x8_UNORM_BLOCK);7709BIND_ENUM_CONSTANT(DATA_FORMAT_ASTC_8x8_SRGB_BLOCK);7710BIND_ENUM_CONSTANT(DATA_FORMAT_ASTC_10x5_UNORM_BLOCK);7711BIND_ENUM_CONSTANT(DATA_FORMAT_ASTC_10x5_SRGB_BLOCK);7712BIND_ENUM_CONSTANT(DATA_FORMAT_ASTC_10x6_UNORM_BLOCK);7713BIND_ENUM_CONSTANT(DATA_FORMAT_ASTC_10x6_SRGB_BLOCK);7714BIND_ENUM_CONSTANT(DATA_FORMAT_ASTC_10x8_UNORM_BLOCK);7715BIND_ENUM_CONSTANT(DATA_FORMAT_ASTC_10x8_SRGB_BLOCK);7716BIND_ENUM_CONSTANT(DATA_FORMAT_ASTC_10x10_UNORM_BLOCK);7717BIND_ENUM_CONSTANT(DATA_FORMAT_ASTC_10x10_SRGB_BLOCK);7718BIND_ENUM_CONSTANT(DATA_FORMAT_ASTC_12x10_UNORM_BLOCK);7719BIND_ENUM_CONSTANT(DATA_FORMAT_ASTC_12x10_SRGB_BLOCK);7720BIND_ENUM_CONSTANT(DATA_FORMAT_ASTC_12x12_UNORM_BLOCK);7721BIND_ENUM_CONSTANT(DATA_FORMAT_ASTC_12x12_SRGB_BLOCK);7722BIND_ENUM_CONSTANT(DATA_FORMAT_G8B8G8R8_422_UNORM);7723BIND_ENUM_CONSTANT(DATA_FORMAT_B8G8R8G8_422_UNORM);7724BIND_ENUM_CONSTANT(DATA_FORMAT_G8_B8_R8_3PLANE_420_UNORM);7725BIND_ENUM_CONSTANT(DATA_FORMAT_G8_B8R8_2PLANE_420_UNORM);7726BIND_ENUM_CONSTANT(DATA_FORMAT_G8_B8_R8_3PLANE_422_UNORM);7727BIND_ENUM_CONSTANT(DATA_FORMAT_G8_B8R8_2PLANE_422_UNORM);7728BIND_ENUM_CONSTANT(DATA_FORMAT_G8_B8_R8_3PLANE_444_UNORM);7729BIND_ENUM_CONSTANT(DATA_FORMAT_R10X6_UNORM_PACK16);7730BIND_ENUM_CONSTANT(DATA_FORMAT_R10X6G10X6_UNORM_2PACK16);7731BIND_ENUM_CONSTANT(DATA_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16);7732BIND_ENUM_CONSTANT(DATA_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16);7733BIND_ENUM_CONSTANT(DATA_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16);7734BIND_ENUM_CONSTANT(DATA_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16);7735BIND_ENUM_CONSTANT(DATA_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16);7736BIND_ENUM_CONSTANT(DATA_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16);7737BIND_ENUM_CONSTANT(DATA_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16);7738BIND_ENUM_CONSTANT(DATA_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16);7739BIND_ENUM_CONSTANT(DATA_FORMAT_R12X4_UNORM_PACK16);7740BIND_ENUM_CONSTANT(DATA_FORMAT_R12X4G12X4_UNORM_2PACK16);7741BIND_ENUM_CONSTANT(DATA_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16);7742BIND_ENUM_CONSTANT(DATA_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16);7743BIND_ENUM_CONSTANT(DATA_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16);7744BIND_ENUM_CONSTANT(DATA_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16);7745BIND_ENUM_CONSTANT(DATA_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16);7746BIND_ENUM_CONSTANT(DATA_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16);7747BIND_ENUM_CONSTANT(DATA_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16);7748BIND_ENUM_CONSTANT(DATA_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16);7749BIND_ENUM_CONSTANT(DATA_FORMAT_G16B16G16R16_422_UNORM);7750BIND_ENUM_CONSTANT(DATA_FORMAT_B16G16R16G16_422_UNORM);7751BIND_ENUM_CONSTANT(DATA_FORMAT_G16_B16_R16_3PLANE_420_UNORM);7752BIND_ENUM_CONSTANT(DATA_FORMAT_G16_B16R16_2PLANE_420_UNORM);7753BIND_ENUM_CONSTANT(DATA_FORMAT_G16_B16_R16_3PLANE_422_UNORM);7754BIND_ENUM_CONSTANT(DATA_FORMAT_G16_B16R16_2PLANE_422_UNORM);7755BIND_ENUM_CONSTANT(DATA_FORMAT_G16_B16_R16_3PLANE_444_UNORM);7756BIND_ENUM_CONSTANT(DATA_FORMAT_ASTC_4x4_SFLOAT_BLOCK);7757BIND_ENUM_CONSTANT(DATA_FORMAT_ASTC_5x4_SFLOAT_BLOCK);7758BIND_ENUM_CONSTANT(DATA_FORMAT_ASTC_5x5_SFLOAT_BLOCK);7759BIND_ENUM_CONSTANT(DATA_FORMAT_ASTC_6x5_SFLOAT_BLOCK);7760BIND_ENUM_CONSTANT(DATA_FORMAT_ASTC_6x6_SFLOAT_BLOCK);7761BIND_ENUM_CONSTANT(DATA_FORMAT_ASTC_8x5_SFLOAT_BLOCK);7762BIND_ENUM_CONSTANT(DATA_FORMAT_ASTC_8x6_SFLOAT_BLOCK);7763BIND_ENUM_CONSTANT(DATA_FORMAT_ASTC_8x8_SFLOAT_BLOCK);7764BIND_ENUM_CONSTANT(DATA_FORMAT_ASTC_10x5_SFLOAT_BLOCK);7765BIND_ENUM_CONSTANT(DATA_FORMAT_ASTC_10x6_SFLOAT_BLOCK);7766BIND_ENUM_CONSTANT(DATA_FORMAT_ASTC_10x8_SFLOAT_BLOCK);7767BIND_ENUM_CONSTANT(DATA_FORMAT_ASTC_10x10_SFLOAT_BLOCK);7768BIND_ENUM_CONSTANT(DATA_FORMAT_ASTC_12x10_SFLOAT_BLOCK);7769BIND_ENUM_CONSTANT(DATA_FORMAT_ASTC_12x12_SFLOAT_BLOCK);7770BIND_ENUM_CONSTANT(DATA_FORMAT_MAX);77717772#ifndef DISABLE_DEPRECATED7773BIND_BITFIELD_FLAG(BARRIER_MASK_VERTEX);7774BIND_BITFIELD_FLAG(BARRIER_MASK_FRAGMENT);7775BIND_BITFIELD_FLAG(BARRIER_MASK_COMPUTE);7776BIND_BITFIELD_FLAG(BARRIER_MASK_TRANSFER);7777BIND_BITFIELD_FLAG(BARRIER_MASK_RASTER);7778BIND_BITFIELD_FLAG(BARRIER_MASK_ALL_BARRIERS);7779BIND_BITFIELD_FLAG(BARRIER_MASK_NO_BARRIER);7780#endif77817782BIND_ENUM_CONSTANT(TEXTURE_TYPE_1D);7783BIND_ENUM_CONSTANT(TEXTURE_TYPE_2D);7784BIND_ENUM_CONSTANT(TEXTURE_TYPE_3D);7785BIND_ENUM_CONSTANT(TEXTURE_TYPE_CUBE);7786BIND_ENUM_CONSTANT(TEXTURE_TYPE_1D_ARRAY);7787BIND_ENUM_CONSTANT(TEXTURE_TYPE_2D_ARRAY);7788BIND_ENUM_CONSTANT(TEXTURE_TYPE_CUBE_ARRAY);7789BIND_ENUM_CONSTANT(TEXTURE_TYPE_MAX);77907791BIND_ENUM_CONSTANT(TEXTURE_SAMPLES_1);7792BIND_ENUM_CONSTANT(TEXTURE_SAMPLES_2);7793BIND_ENUM_CONSTANT(TEXTURE_SAMPLES_4);7794BIND_ENUM_CONSTANT(TEXTURE_SAMPLES_8);7795BIND_ENUM_CONSTANT(TEXTURE_SAMPLES_16);7796BIND_ENUM_CONSTANT(TEXTURE_SAMPLES_32);7797BIND_ENUM_CONSTANT(TEXTURE_SAMPLES_64);7798BIND_ENUM_CONSTANT(TEXTURE_SAMPLES_MAX);77997800BIND_BITFIELD_FLAG(TEXTURE_USAGE_SAMPLING_BIT);7801BIND_BITFIELD_FLAG(TEXTURE_USAGE_COLOR_ATTACHMENT_BIT);7802BIND_BITFIELD_FLAG(TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT);7803BIND_BITFIELD_FLAG(TEXTURE_USAGE_STORAGE_BIT);7804BIND_BITFIELD_FLAG(TEXTURE_USAGE_STORAGE_ATOMIC_BIT);7805BIND_BITFIELD_FLAG(TEXTURE_USAGE_CPU_READ_BIT);7806BIND_BITFIELD_FLAG(TEXTURE_USAGE_CAN_UPDATE_BIT);7807BIND_BITFIELD_FLAG(TEXTURE_USAGE_CAN_COPY_FROM_BIT);7808BIND_BITFIELD_FLAG(TEXTURE_USAGE_CAN_COPY_TO_BIT);7809BIND_BITFIELD_FLAG(TEXTURE_USAGE_INPUT_ATTACHMENT_BIT);78107811BIND_ENUM_CONSTANT(TEXTURE_SWIZZLE_IDENTITY);7812BIND_ENUM_CONSTANT(TEXTURE_SWIZZLE_ZERO);7813BIND_ENUM_CONSTANT(TEXTURE_SWIZZLE_ONE);7814BIND_ENUM_CONSTANT(TEXTURE_SWIZZLE_R);7815BIND_ENUM_CONSTANT(TEXTURE_SWIZZLE_G);7816BIND_ENUM_CONSTANT(TEXTURE_SWIZZLE_B);7817BIND_ENUM_CONSTANT(TEXTURE_SWIZZLE_A);7818BIND_ENUM_CONSTANT(TEXTURE_SWIZZLE_MAX);78197820BIND_ENUM_CONSTANT(TEXTURE_SLICE_2D);7821BIND_ENUM_CONSTANT(TEXTURE_SLICE_CUBEMAP);7822BIND_ENUM_CONSTANT(TEXTURE_SLICE_3D);78237824BIND_ENUM_CONSTANT(SAMPLER_FILTER_NEAREST);7825BIND_ENUM_CONSTANT(SAMPLER_FILTER_LINEAR);7826BIND_ENUM_CONSTANT(SAMPLER_REPEAT_MODE_REPEAT);7827BIND_ENUM_CONSTANT(SAMPLER_REPEAT_MODE_MIRRORED_REPEAT);7828BIND_ENUM_CONSTANT(SAMPLER_REPEAT_MODE_CLAMP_TO_EDGE);7829BIND_ENUM_CONSTANT(SAMPLER_REPEAT_MODE_CLAMP_TO_BORDER);7830BIND_ENUM_CONSTANT(SAMPLER_REPEAT_MODE_MIRROR_CLAMP_TO_EDGE);7831BIND_ENUM_CONSTANT(SAMPLER_REPEAT_MODE_MAX);78327833BIND_ENUM_CONSTANT(SAMPLER_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK);7834BIND_ENUM_CONSTANT(SAMPLER_BORDER_COLOR_INT_TRANSPARENT_BLACK);7835BIND_ENUM_CONSTANT(SAMPLER_BORDER_COLOR_FLOAT_OPAQUE_BLACK);7836BIND_ENUM_CONSTANT(SAMPLER_BORDER_COLOR_INT_OPAQUE_BLACK);7837BIND_ENUM_CONSTANT(SAMPLER_BORDER_COLOR_FLOAT_OPAQUE_WHITE);7838BIND_ENUM_CONSTANT(SAMPLER_BORDER_COLOR_INT_OPAQUE_WHITE);7839BIND_ENUM_CONSTANT(SAMPLER_BORDER_COLOR_MAX);78407841BIND_ENUM_CONSTANT(VERTEX_FREQUENCY_VERTEX);7842BIND_ENUM_CONSTANT(VERTEX_FREQUENCY_INSTANCE);78437844BIND_ENUM_CONSTANT(INDEX_BUFFER_FORMAT_UINT16);7845BIND_ENUM_CONSTANT(INDEX_BUFFER_FORMAT_UINT32);78467847BIND_BITFIELD_FLAG(STORAGE_BUFFER_USAGE_DISPATCH_INDIRECT);78487849BIND_BITFIELD_FLAG(BUFFER_CREATION_DEVICE_ADDRESS_BIT);7850BIND_BITFIELD_FLAG(BUFFER_CREATION_AS_STORAGE_BIT);78517852BIND_ENUM_CONSTANT(UNIFORM_TYPE_SAMPLER); //for sampling only (sampler GLSL type)7853BIND_ENUM_CONSTANT(UNIFORM_TYPE_SAMPLER_WITH_TEXTURE); // for sampling only); but includes a texture); (samplerXX GLSL type)); first a sampler then a texture7854BIND_ENUM_CONSTANT(UNIFORM_TYPE_TEXTURE); //only texture); (textureXX GLSL type)7855BIND_ENUM_CONSTANT(UNIFORM_TYPE_IMAGE); // storage image (imageXX GLSL type)); for compute mostly7856BIND_ENUM_CONSTANT(UNIFORM_TYPE_TEXTURE_BUFFER); // buffer texture (or TBO); textureBuffer type)7857BIND_ENUM_CONSTANT(UNIFORM_TYPE_SAMPLER_WITH_TEXTURE_BUFFER); // buffer texture with a sampler(or TBO); samplerBuffer type)7858BIND_ENUM_CONSTANT(UNIFORM_TYPE_IMAGE_BUFFER); //texel buffer); (imageBuffer type)); for compute mostly7859BIND_ENUM_CONSTANT(UNIFORM_TYPE_UNIFORM_BUFFER); //regular uniform buffer (or UBO).7860BIND_ENUM_CONSTANT(UNIFORM_TYPE_STORAGE_BUFFER); //storage buffer ("buffer" qualifier) like UBO); but supports storage); for compute mostly7861BIND_ENUM_CONSTANT(UNIFORM_TYPE_INPUT_ATTACHMENT); //used for sub-pass read/write); for mobile mostly7862BIND_ENUM_CONSTANT(UNIFORM_TYPE_MAX);78637864BIND_ENUM_CONSTANT(RENDER_PRIMITIVE_POINTS);7865BIND_ENUM_CONSTANT(RENDER_PRIMITIVE_LINES);7866BIND_ENUM_CONSTANT(RENDER_PRIMITIVE_LINES_WITH_ADJACENCY);7867BIND_ENUM_CONSTANT(RENDER_PRIMITIVE_LINESTRIPS);7868BIND_ENUM_CONSTANT(RENDER_PRIMITIVE_LINESTRIPS_WITH_ADJACENCY);7869BIND_ENUM_CONSTANT(RENDER_PRIMITIVE_TRIANGLES);7870BIND_ENUM_CONSTANT(RENDER_PRIMITIVE_TRIANGLES_WITH_ADJACENCY);7871BIND_ENUM_CONSTANT(RENDER_PRIMITIVE_TRIANGLE_STRIPS);7872BIND_ENUM_CONSTANT(RENDER_PRIMITIVE_TRIANGLE_STRIPS_WITH_AJACENCY);7873BIND_ENUM_CONSTANT(RENDER_PRIMITIVE_TRIANGLE_STRIPS_WITH_RESTART_INDEX);7874BIND_ENUM_CONSTANT(RENDER_PRIMITIVE_TESSELATION_PATCH);7875BIND_ENUM_CONSTANT(RENDER_PRIMITIVE_MAX);78767877BIND_ENUM_CONSTANT(POLYGON_CULL_DISABLED);7878BIND_ENUM_CONSTANT(POLYGON_CULL_FRONT);7879BIND_ENUM_CONSTANT(POLYGON_CULL_BACK);78807881BIND_ENUM_CONSTANT(POLYGON_FRONT_FACE_CLOCKWISE);7882BIND_ENUM_CONSTANT(POLYGON_FRONT_FACE_COUNTER_CLOCKWISE);78837884BIND_ENUM_CONSTANT(STENCIL_OP_KEEP);7885BIND_ENUM_CONSTANT(STENCIL_OP_ZERO);7886BIND_ENUM_CONSTANT(STENCIL_OP_REPLACE);7887BIND_ENUM_CONSTANT(STENCIL_OP_INCREMENT_AND_CLAMP);7888BIND_ENUM_CONSTANT(STENCIL_OP_DECREMENT_AND_CLAMP);7889BIND_ENUM_CONSTANT(STENCIL_OP_INVERT);7890BIND_ENUM_CONSTANT(STENCIL_OP_INCREMENT_AND_WRAP);7891BIND_ENUM_CONSTANT(STENCIL_OP_DECREMENT_AND_WRAP);7892BIND_ENUM_CONSTANT(STENCIL_OP_MAX); //not an actual operator); just the amount of operators :D78937894BIND_ENUM_CONSTANT(COMPARE_OP_NEVER);7895BIND_ENUM_CONSTANT(COMPARE_OP_LESS);7896BIND_ENUM_CONSTANT(COMPARE_OP_EQUAL);7897BIND_ENUM_CONSTANT(COMPARE_OP_LESS_OR_EQUAL);7898BIND_ENUM_CONSTANT(COMPARE_OP_GREATER);7899BIND_ENUM_CONSTANT(COMPARE_OP_NOT_EQUAL);7900BIND_ENUM_CONSTANT(COMPARE_OP_GREATER_OR_EQUAL);7901BIND_ENUM_CONSTANT(COMPARE_OP_ALWAYS);7902BIND_ENUM_CONSTANT(COMPARE_OP_MAX);79037904BIND_ENUM_CONSTANT(LOGIC_OP_CLEAR);7905BIND_ENUM_CONSTANT(LOGIC_OP_AND);7906BIND_ENUM_CONSTANT(LOGIC_OP_AND_REVERSE);7907BIND_ENUM_CONSTANT(LOGIC_OP_COPY);7908BIND_ENUM_CONSTANT(LOGIC_OP_AND_INVERTED);7909BIND_ENUM_CONSTANT(LOGIC_OP_NO_OP);7910BIND_ENUM_CONSTANT(LOGIC_OP_XOR);7911BIND_ENUM_CONSTANT(LOGIC_OP_OR);7912BIND_ENUM_CONSTANT(LOGIC_OP_NOR);7913BIND_ENUM_CONSTANT(LOGIC_OP_EQUIVALENT);7914BIND_ENUM_CONSTANT(LOGIC_OP_INVERT);7915BIND_ENUM_CONSTANT(LOGIC_OP_OR_REVERSE);7916BIND_ENUM_CONSTANT(LOGIC_OP_COPY_INVERTED);7917BIND_ENUM_CONSTANT(LOGIC_OP_OR_INVERTED);7918BIND_ENUM_CONSTANT(LOGIC_OP_NAND);7919BIND_ENUM_CONSTANT(LOGIC_OP_SET);7920BIND_ENUM_CONSTANT(LOGIC_OP_MAX); //not an actual operator); just the amount of operators :D79217922BIND_ENUM_CONSTANT(BLEND_FACTOR_ZERO);7923BIND_ENUM_CONSTANT(BLEND_FACTOR_ONE);7924BIND_ENUM_CONSTANT(BLEND_FACTOR_SRC_COLOR);7925BIND_ENUM_CONSTANT(BLEND_FACTOR_ONE_MINUS_SRC_COLOR);7926BIND_ENUM_CONSTANT(BLEND_FACTOR_DST_COLOR);7927BIND_ENUM_CONSTANT(BLEND_FACTOR_ONE_MINUS_DST_COLOR);7928BIND_ENUM_CONSTANT(BLEND_FACTOR_SRC_ALPHA);7929BIND_ENUM_CONSTANT(BLEND_FACTOR_ONE_MINUS_SRC_ALPHA);7930BIND_ENUM_CONSTANT(BLEND_FACTOR_DST_ALPHA);7931BIND_ENUM_CONSTANT(BLEND_FACTOR_ONE_MINUS_DST_ALPHA);7932BIND_ENUM_CONSTANT(BLEND_FACTOR_CONSTANT_COLOR);7933BIND_ENUM_CONSTANT(BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR);7934BIND_ENUM_CONSTANT(BLEND_FACTOR_CONSTANT_ALPHA);7935BIND_ENUM_CONSTANT(BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA);7936BIND_ENUM_CONSTANT(BLEND_FACTOR_SRC_ALPHA_SATURATE);7937BIND_ENUM_CONSTANT(BLEND_FACTOR_SRC1_COLOR);7938BIND_ENUM_CONSTANT(BLEND_FACTOR_ONE_MINUS_SRC1_COLOR);7939BIND_ENUM_CONSTANT(BLEND_FACTOR_SRC1_ALPHA);7940BIND_ENUM_CONSTANT(BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA);7941BIND_ENUM_CONSTANT(BLEND_FACTOR_MAX);79427943BIND_ENUM_CONSTANT(BLEND_OP_ADD);7944BIND_ENUM_CONSTANT(BLEND_OP_SUBTRACT);7945BIND_ENUM_CONSTANT(BLEND_OP_REVERSE_SUBTRACT);7946BIND_ENUM_CONSTANT(BLEND_OP_MINIMUM);7947BIND_ENUM_CONSTANT(BLEND_OP_MAXIMUM);7948BIND_ENUM_CONSTANT(BLEND_OP_MAX);79497950BIND_BITFIELD_FLAG(DYNAMIC_STATE_LINE_WIDTH);7951BIND_BITFIELD_FLAG(DYNAMIC_STATE_DEPTH_BIAS);7952BIND_BITFIELD_FLAG(DYNAMIC_STATE_BLEND_CONSTANTS);7953BIND_BITFIELD_FLAG(DYNAMIC_STATE_DEPTH_BOUNDS);7954BIND_BITFIELD_FLAG(DYNAMIC_STATE_STENCIL_COMPARE_MASK);7955BIND_BITFIELD_FLAG(DYNAMIC_STATE_STENCIL_WRITE_MASK);7956BIND_BITFIELD_FLAG(DYNAMIC_STATE_STENCIL_REFERENCE);79577958#ifndef DISABLE_DEPRECATED7959BIND_ENUM_CONSTANT(INITIAL_ACTION_LOAD);7960BIND_ENUM_CONSTANT(INITIAL_ACTION_CLEAR);7961BIND_ENUM_CONSTANT(INITIAL_ACTION_DISCARD);7962BIND_ENUM_CONSTANT(INITIAL_ACTION_MAX);7963BIND_ENUM_CONSTANT(INITIAL_ACTION_CLEAR_REGION);7964BIND_ENUM_CONSTANT(INITIAL_ACTION_CLEAR_REGION_CONTINUE);7965BIND_ENUM_CONSTANT(INITIAL_ACTION_KEEP);7966BIND_ENUM_CONSTANT(INITIAL_ACTION_DROP);7967BIND_ENUM_CONSTANT(INITIAL_ACTION_CONTINUE);79687969BIND_ENUM_CONSTANT(FINAL_ACTION_STORE);7970BIND_ENUM_CONSTANT(FINAL_ACTION_DISCARD);7971BIND_ENUM_CONSTANT(FINAL_ACTION_MAX);7972BIND_ENUM_CONSTANT(FINAL_ACTION_READ);7973BIND_ENUM_CONSTANT(FINAL_ACTION_CONTINUE);7974#endif79757976BIND_ENUM_CONSTANT(SHADER_STAGE_VERTEX);7977BIND_ENUM_CONSTANT(SHADER_STAGE_FRAGMENT);7978BIND_ENUM_CONSTANT(SHADER_STAGE_TESSELATION_CONTROL);7979BIND_ENUM_CONSTANT(SHADER_STAGE_TESSELATION_EVALUATION);7980BIND_ENUM_CONSTANT(SHADER_STAGE_COMPUTE);7981BIND_ENUM_CONSTANT(SHADER_STAGE_MAX);7982BIND_ENUM_CONSTANT(SHADER_STAGE_VERTEX_BIT);7983BIND_ENUM_CONSTANT(SHADER_STAGE_FRAGMENT_BIT);7984BIND_ENUM_CONSTANT(SHADER_STAGE_TESSELATION_CONTROL_BIT);7985BIND_ENUM_CONSTANT(SHADER_STAGE_TESSELATION_EVALUATION_BIT);7986BIND_ENUM_CONSTANT(SHADER_STAGE_COMPUTE_BIT);79877988BIND_ENUM_CONSTANT(SHADER_LANGUAGE_GLSL);7989BIND_ENUM_CONSTANT(SHADER_LANGUAGE_HLSL);79907991BIND_ENUM_CONSTANT(PIPELINE_SPECIALIZATION_CONSTANT_TYPE_BOOL);7992BIND_ENUM_CONSTANT(PIPELINE_SPECIALIZATION_CONSTANT_TYPE_INT);7993BIND_ENUM_CONSTANT(PIPELINE_SPECIALIZATION_CONSTANT_TYPE_FLOAT);79947995BIND_ENUM_CONSTANT(SUPPORTS_METALFX_SPATIAL);7996BIND_ENUM_CONSTANT(SUPPORTS_METALFX_TEMPORAL);7997BIND_ENUM_CONSTANT(SUPPORTS_BUFFER_DEVICE_ADDRESS);7998BIND_ENUM_CONSTANT(SUPPORTS_IMAGE_ATOMIC_32_BIT);79998000BIND_ENUM_CONSTANT(LIMIT_MAX_BOUND_UNIFORM_SETS);8001BIND_ENUM_CONSTANT(LIMIT_MAX_FRAMEBUFFER_COLOR_ATTACHMENTS);8002BIND_ENUM_CONSTANT(LIMIT_MAX_TEXTURES_PER_UNIFORM_SET);8003BIND_ENUM_CONSTANT(LIMIT_MAX_SAMPLERS_PER_UNIFORM_SET);8004BIND_ENUM_CONSTANT(LIMIT_MAX_STORAGE_BUFFERS_PER_UNIFORM_SET);8005BIND_ENUM_CONSTANT(LIMIT_MAX_STORAGE_IMAGES_PER_UNIFORM_SET);8006BIND_ENUM_CONSTANT(LIMIT_MAX_UNIFORM_BUFFERS_PER_UNIFORM_SET);8007BIND_ENUM_CONSTANT(LIMIT_MAX_DRAW_INDEXED_INDEX);8008BIND_ENUM_CONSTANT(LIMIT_MAX_FRAMEBUFFER_HEIGHT);8009BIND_ENUM_CONSTANT(LIMIT_MAX_FRAMEBUFFER_WIDTH);8010BIND_ENUM_CONSTANT(LIMIT_MAX_TEXTURE_ARRAY_LAYERS);8011BIND_ENUM_CONSTANT(LIMIT_MAX_TEXTURE_SIZE_1D);8012BIND_ENUM_CONSTANT(LIMIT_MAX_TEXTURE_SIZE_2D);8013BIND_ENUM_CONSTANT(LIMIT_MAX_TEXTURE_SIZE_3D);8014BIND_ENUM_CONSTANT(LIMIT_MAX_TEXTURE_SIZE_CUBE);8015BIND_ENUM_CONSTANT(LIMIT_MAX_TEXTURES_PER_SHADER_STAGE);8016BIND_ENUM_CONSTANT(LIMIT_MAX_SAMPLERS_PER_SHADER_STAGE);8017BIND_ENUM_CONSTANT(LIMIT_MAX_STORAGE_BUFFERS_PER_SHADER_STAGE);8018BIND_ENUM_CONSTANT(LIMIT_MAX_STORAGE_IMAGES_PER_SHADER_STAGE);8019BIND_ENUM_CONSTANT(LIMIT_MAX_UNIFORM_BUFFERS_PER_SHADER_STAGE);8020BIND_ENUM_CONSTANT(LIMIT_MAX_PUSH_CONSTANT_SIZE);8021BIND_ENUM_CONSTANT(LIMIT_MAX_UNIFORM_BUFFER_SIZE);8022BIND_ENUM_CONSTANT(LIMIT_MAX_VERTEX_INPUT_ATTRIBUTE_OFFSET);8023BIND_ENUM_CONSTANT(LIMIT_MAX_VERTEX_INPUT_ATTRIBUTES);8024BIND_ENUM_CONSTANT(LIMIT_MAX_VERTEX_INPUT_BINDINGS);8025BIND_ENUM_CONSTANT(LIMIT_MAX_VERTEX_INPUT_BINDING_STRIDE);8026BIND_ENUM_CONSTANT(LIMIT_MIN_UNIFORM_BUFFER_OFFSET_ALIGNMENT);8027BIND_ENUM_CONSTANT(LIMIT_MAX_COMPUTE_SHARED_MEMORY_SIZE);8028BIND_ENUM_CONSTANT(LIMIT_MAX_COMPUTE_WORKGROUP_COUNT_X);8029BIND_ENUM_CONSTANT(LIMIT_MAX_COMPUTE_WORKGROUP_COUNT_Y);8030BIND_ENUM_CONSTANT(LIMIT_MAX_COMPUTE_WORKGROUP_COUNT_Z);8031BIND_ENUM_CONSTANT(LIMIT_MAX_COMPUTE_WORKGROUP_INVOCATIONS);8032BIND_ENUM_CONSTANT(LIMIT_MAX_COMPUTE_WORKGROUP_SIZE_X);8033BIND_ENUM_CONSTANT(LIMIT_MAX_COMPUTE_WORKGROUP_SIZE_Y);8034BIND_ENUM_CONSTANT(LIMIT_MAX_COMPUTE_WORKGROUP_SIZE_Z);8035BIND_ENUM_CONSTANT(LIMIT_MAX_VIEWPORT_DIMENSIONS_X);8036BIND_ENUM_CONSTANT(LIMIT_MAX_VIEWPORT_DIMENSIONS_Y);8037BIND_ENUM_CONSTANT(LIMIT_METALFX_TEMPORAL_SCALER_MIN_SCALE);8038BIND_ENUM_CONSTANT(LIMIT_METALFX_TEMPORAL_SCALER_MAX_SCALE);80398040BIND_ENUM_CONSTANT(MEMORY_TEXTURES);8041BIND_ENUM_CONSTANT(MEMORY_BUFFERS);8042BIND_ENUM_CONSTANT(MEMORY_TOTAL);80438044BIND_CONSTANT(INVALID_ID);8045BIND_CONSTANT(INVALID_FORMAT_ID);80468047BIND_ENUM_CONSTANT(NONE);8048BIND_ENUM_CONSTANT(REFLECTION_PROBES);8049BIND_ENUM_CONSTANT(SKY_PASS);8050BIND_ENUM_CONSTANT(LIGHTMAPPER_PASS);8051BIND_ENUM_CONSTANT(SHADOW_PASS_DIRECTIONAL);8052BIND_ENUM_CONSTANT(SHADOW_PASS_CUBE);8053BIND_ENUM_CONSTANT(OPAQUE_PASS);8054BIND_ENUM_CONSTANT(ALPHA_PASS);8055BIND_ENUM_CONSTANT(TRANSPARENT_PASS);8056BIND_ENUM_CONSTANT(POST_PROCESSING_PASS);8057BIND_ENUM_CONSTANT(BLIT_PASS);8058BIND_ENUM_CONSTANT(UI_PASS);8059BIND_ENUM_CONSTANT(DEBUG_PASS);80608061BIND_BITFIELD_FLAG(DRAW_DEFAULT_ALL);8062BIND_BITFIELD_FLAG(DRAW_CLEAR_COLOR_0);8063BIND_BITFIELD_FLAG(DRAW_CLEAR_COLOR_1);8064BIND_BITFIELD_FLAG(DRAW_CLEAR_COLOR_2);8065BIND_BITFIELD_FLAG(DRAW_CLEAR_COLOR_3);8066BIND_BITFIELD_FLAG(DRAW_CLEAR_COLOR_4);8067BIND_BITFIELD_FLAG(DRAW_CLEAR_COLOR_5);8068BIND_BITFIELD_FLAG(DRAW_CLEAR_COLOR_6);8069BIND_BITFIELD_FLAG(DRAW_CLEAR_COLOR_7);8070BIND_BITFIELD_FLAG(DRAW_CLEAR_COLOR_MASK);8071BIND_BITFIELD_FLAG(DRAW_CLEAR_COLOR_ALL);8072BIND_BITFIELD_FLAG(DRAW_IGNORE_COLOR_0);8073BIND_BITFIELD_FLAG(DRAW_IGNORE_COLOR_1);8074BIND_BITFIELD_FLAG(DRAW_IGNORE_COLOR_2);8075BIND_BITFIELD_FLAG(DRAW_IGNORE_COLOR_3);8076BIND_BITFIELD_FLAG(DRAW_IGNORE_COLOR_4);8077BIND_BITFIELD_FLAG(DRAW_IGNORE_COLOR_5);8078BIND_BITFIELD_FLAG(DRAW_IGNORE_COLOR_6);8079BIND_BITFIELD_FLAG(DRAW_IGNORE_COLOR_7);8080BIND_BITFIELD_FLAG(DRAW_IGNORE_COLOR_MASK);8081BIND_BITFIELD_FLAG(DRAW_IGNORE_COLOR_ALL);8082BIND_BITFIELD_FLAG(DRAW_CLEAR_DEPTH);8083BIND_BITFIELD_FLAG(DRAW_IGNORE_DEPTH);8084BIND_BITFIELD_FLAG(DRAW_CLEAR_STENCIL);8085BIND_BITFIELD_FLAG(DRAW_IGNORE_STENCIL);8086BIND_BITFIELD_FLAG(DRAW_CLEAR_ALL);8087BIND_BITFIELD_FLAG(DRAW_IGNORE_ALL);8088}80898090void RenderingDevice::make_current() {8091render_thread_id = Thread::get_caller_id();8092}80938094RenderingDevice::~RenderingDevice() {8095finalize();80968097if (singleton == this) {8098singleton = nullptr;8099}8100}81018102RenderingDevice::RenderingDevice() {8103if (singleton == nullptr) {8104singleton = this;8105}81068107render_thread_id = Thread::get_caller_id();8108}81098110/*****************/8111/**** BINDERS ****/8112/*****************/81138114RID RenderingDevice::_texture_create(const Ref<RDTextureFormat> &p_format, const Ref<RDTextureView> &p_view, const TypedArray<PackedByteArray> &p_data) {8115ERR_FAIL_COND_V(p_format.is_null(), RID());8116ERR_FAIL_COND_V(p_view.is_null(), RID());8117Vector<Vector<uint8_t>> data;8118for (int i = 0; i < p_data.size(); i++) {8119Vector<uint8_t> byte_slice = p_data[i];8120ERR_FAIL_COND_V(byte_slice.is_empty(), RID());8121data.push_back(byte_slice);8122}8123return texture_create(p_format->base, p_view->base, data);8124}81258126RID RenderingDevice::_texture_create_shared(const Ref<RDTextureView> &p_view, RID p_with_texture) {8127ERR_FAIL_COND_V(p_view.is_null(), RID());81288129return texture_create_shared(p_view->base, p_with_texture);8130}81318132RID 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) {8133ERR_FAIL_COND_V(p_view.is_null(), RID());81348135return texture_create_shared_from_slice(p_view->base, p_with_texture, p_layer, p_mipmap, p_mipmaps, p_slice_type);8136}81378138Ref<RDTextureFormat> RenderingDevice::_texture_get_format(RID p_rd_texture) {8139Ref<RDTextureFormat> rtf;8140rtf.instantiate();8141rtf->base = texture_get_format(p_rd_texture);81428143return rtf;8144}81458146RenderingDevice::FramebufferFormatID RenderingDevice::_framebuffer_format_create(const TypedArray<RDAttachmentFormat> &p_attachments, uint32_t p_view_count) {8147Vector<AttachmentFormat> attachments;8148attachments.resize(p_attachments.size());81498150for (int i = 0; i < p_attachments.size(); i++) {8151Ref<RDAttachmentFormat> af = p_attachments[i];8152ERR_FAIL_COND_V(af.is_null(), INVALID_FORMAT_ID);8153attachments.write[i] = af->base;8154}8155return framebuffer_format_create(attachments, p_view_count);8156}81578158RenderingDevice::FramebufferFormatID RenderingDevice::_framebuffer_format_create_multipass(const TypedArray<RDAttachmentFormat> &p_attachments, const TypedArray<RDFramebufferPass> &p_passes, uint32_t p_view_count) {8159Vector<AttachmentFormat> attachments;8160attachments.resize(p_attachments.size());81618162for (int i = 0; i < p_attachments.size(); i++) {8163Ref<RDAttachmentFormat> af = p_attachments[i];8164ERR_FAIL_COND_V(af.is_null(), INVALID_FORMAT_ID);8165attachments.write[i] = af->base;8166}81678168Vector<FramebufferPass> passes;8169for (int i = 0; i < p_passes.size(); i++) {8170Ref<RDFramebufferPass> pass = p_passes[i];8171ERR_CONTINUE(pass.is_null());8172passes.push_back(pass->base);8173}81748175return framebuffer_format_create_multipass(attachments, passes, p_view_count);8176}81778178RID RenderingDevice::_framebuffer_create(const TypedArray<RID> &p_textures, FramebufferFormatID p_format_check, uint32_t p_view_count) {8179Vector<RID> textures = Variant(p_textures);8180return framebuffer_create(textures, p_format_check, p_view_count);8181}81828183RID RenderingDevice::_framebuffer_create_multipass(const TypedArray<RID> &p_textures, const TypedArray<RDFramebufferPass> &p_passes, FramebufferFormatID p_format_check, uint32_t p_view_count) {8184Vector<RID> textures = Variant(p_textures);8185Vector<FramebufferPass> passes;8186for (int i = 0; i < p_passes.size(); i++) {8187Ref<RDFramebufferPass> pass = p_passes[i];8188ERR_CONTINUE(pass.is_null());8189passes.push_back(pass->base);8190}8191return framebuffer_create_multipass(textures, passes, p_format_check, p_view_count);8192}81938194RID RenderingDevice::_sampler_create(const Ref<RDSamplerState> &p_state) {8195ERR_FAIL_COND_V(p_state.is_null(), RID());81968197return sampler_create(p_state->base);8198}81998200RenderingDevice::VertexFormatID RenderingDevice::_vertex_format_create(const TypedArray<RDVertexAttribute> &p_vertex_formats) {8201Vector<VertexAttribute> descriptions;8202descriptions.resize(p_vertex_formats.size());82038204for (int i = 0; i < p_vertex_formats.size(); i++) {8205Ref<RDVertexAttribute> af = p_vertex_formats[i];8206ERR_FAIL_COND_V(af.is_null(), INVALID_FORMAT_ID);8207descriptions.write[i] = af->base;8208}8209return vertex_format_create(descriptions);8210}82118212RID 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) {8213Vector<RID> buffers = Variant(p_src_buffers);82148215Vector<uint64_t> offsets;8216offsets.resize(p_offsets.size());8217for (int i = 0; i < p_offsets.size(); i++) {8218offsets.write[i] = p_offsets[i];8219}82208221return vertex_array_create(p_vertex_count, p_vertex_format, buffers, offsets);8222}82238224Ref<RDShaderSPIRV> RenderingDevice::_shader_compile_spirv_from_source(const Ref<RDShaderSource> &p_source, bool p_allow_cache) {8225ERR_FAIL_COND_V(p_source.is_null(), Ref<RDShaderSPIRV>());82268227Ref<RDShaderSPIRV> bytecode;8228bytecode.instantiate();8229for (int i = 0; i < RD::SHADER_STAGE_MAX; i++) {8230String error;82318232ShaderStage stage = ShaderStage(i);8233String source = p_source->get_stage_source(stage);82348235if (!source.is_empty()) {8236Vector<uint8_t> spirv = shader_compile_spirv_from_source(stage, source, p_source->get_language(), &error, p_allow_cache);8237bytecode->set_stage_bytecode(stage, spirv);8238bytecode->set_stage_compile_error(stage, error);8239}8240}8241return bytecode;8242}82438244Vector<uint8_t> RenderingDevice::_shader_compile_binary_from_spirv(const Ref<RDShaderSPIRV> &p_spirv, const String &p_shader_name) {8245ERR_FAIL_COND_V(p_spirv.is_null(), Vector<uint8_t>());82468247Vector<ShaderStageSPIRVData> stage_data;8248for (int i = 0; i < RD::SHADER_STAGE_MAX; i++) {8249ShaderStage stage = ShaderStage(i);8250ShaderStageSPIRVData sd;8251sd.shader_stage = stage;8252String error = p_spirv->get_stage_compile_error(stage);8253ERR_FAIL_COND_V_MSG(!error.is_empty(), Vector<uint8_t>(), "Can't create a shader from an errored bytecode. Check errors in source bytecode.");8254sd.spirv = p_spirv->get_stage_bytecode(stage);8255if (sd.spirv.is_empty()) {8256continue;8257}8258stage_data.push_back(sd);8259}82608261return shader_compile_binary_from_spirv(stage_data, p_shader_name);8262}82638264RID RenderingDevice::_shader_create_from_spirv(const Ref<RDShaderSPIRV> &p_spirv, const String &p_shader_name) {8265ERR_FAIL_COND_V(p_spirv.is_null(), RID());82668267Vector<ShaderStageSPIRVData> stage_data;8268for (int i = 0; i < RD::SHADER_STAGE_MAX; i++) {8269ShaderStage stage = ShaderStage(i);8270ShaderStageSPIRVData sd;8271sd.shader_stage = stage;8272String error = p_spirv->get_stage_compile_error(stage);8273ERR_FAIL_COND_V_MSG(!error.is_empty(), RID(), "Can't create a shader from an errored bytecode. Check errors in source bytecode.");8274sd.spirv = p_spirv->get_stage_bytecode(stage);8275if (sd.spirv.is_empty()) {8276continue;8277}8278stage_data.push_back(sd);8279}8280return shader_create_from_spirv(stage_data);8281}82828283RID RenderingDevice::_uniform_set_create(const TypedArray<RDUniform> &p_uniforms, RID p_shader, uint32_t p_shader_set) {8284LocalVector<Uniform> uniforms;8285uniforms.resize(p_uniforms.size());8286for (int i = 0; i < p_uniforms.size(); i++) {8287Ref<RDUniform> uniform = p_uniforms[i];8288ERR_FAIL_COND_V(uniform.is_null(), RID());8289uniforms[i] = uniform->base;8290}8291return uniform_set_create(uniforms, p_shader, p_shader_set);8292}82938294Error RenderingDevice::_buffer_update_bind(RID p_buffer, uint32_t p_offset, uint32_t p_size, const Vector<uint8_t> &p_data) {8295return buffer_update(p_buffer, p_offset, p_size, p_data.ptr());8296}82978298static Vector<RenderingDevice::PipelineSpecializationConstant> _get_spec_constants(const TypedArray<RDPipelineSpecializationConstant> &p_constants) {8299Vector<RenderingDevice::PipelineSpecializationConstant> ret;8300ret.resize(p_constants.size());8301for (int i = 0; i < p_constants.size(); i++) {8302Ref<RDPipelineSpecializationConstant> c = p_constants[i];8303ERR_CONTINUE(c.is_null());8304RenderingDevice::PipelineSpecializationConstant &sc = ret.write[i];8305Variant value = c->get_value();8306switch (value.get_type()) {8307case Variant::BOOL: {8308sc.type = RD::PIPELINE_SPECIALIZATION_CONSTANT_TYPE_BOOL;8309sc.bool_value = value;8310} break;8311case Variant::INT: {8312sc.type = RD::PIPELINE_SPECIALIZATION_CONSTANT_TYPE_INT;8313sc.int_value = value;8314} break;8315case Variant::FLOAT: {8316sc.type = RD::PIPELINE_SPECIALIZATION_CONSTANT_TYPE_FLOAT;8317sc.float_value = value;8318} break;8319default: {8320}8321}83228323sc.constant_id = c->get_constant_id();8324}8325return ret;8326}83278328RID 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) {8329PipelineRasterizationState rasterization_state;8330if (p_rasterization_state.is_valid()) {8331rasterization_state = p_rasterization_state->base;8332}83338334PipelineMultisampleState multisample_state;8335if (p_multisample_state.is_valid()) {8336multisample_state = p_multisample_state->base;8337for (int i = 0; i < p_multisample_state->sample_masks.size(); i++) {8338int64_t mask = p_multisample_state->sample_masks[i];8339multisample_state.sample_mask.push_back(mask);8340}8341}83428343PipelineDepthStencilState depth_stencil_state;8344if (p_depth_stencil_state.is_valid()) {8345depth_stencil_state = p_depth_stencil_state->base;8346}83478348PipelineColorBlendState color_blend_state;8349if (p_blend_state.is_valid()) {8350color_blend_state = p_blend_state->base;8351for (int i = 0; i < p_blend_state->attachments.size(); i++) {8352Ref<RDPipelineColorBlendStateAttachment> attachment = p_blend_state->attachments[i];8353if (attachment.is_valid()) {8354color_blend_state.attachments.push_back(attachment->base);8355}8356}8357}83588359return 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));8360}83618362RID RenderingDevice::_compute_pipeline_create(RID p_shader, const TypedArray<RDPipelineSpecializationConstant> &p_specialization_constants = TypedArray<RDPipelineSpecializationConstant>()) {8363return compute_pipeline_create(p_shader, _get_spec_constants(p_specialization_constants));8364}83658366#ifndef DISABLE_DEPRECATED8367Vector<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) {8368ERR_FAIL_V_MSG(Vector<int64_t>(), "Deprecated. Split draw lists are used automatically by RenderingDevice.");8369}83708371Vector<int64_t> RenderingDevice::_draw_list_switch_to_next_pass_split(uint32_t p_splits) {8372ERR_FAIL_V_MSG(Vector<int64_t>(), "Deprecated. Split draw lists are used automatically by RenderingDevice.");8373}8374#endif83758376void RenderingDevice::_draw_list_set_push_constant(DrawListID p_list, const Vector<uint8_t> &p_data, uint32_t p_data_size) {8377ERR_FAIL_COND(p_data_size > (uint32_t)p_data.size());8378draw_list_set_push_constant(p_list, p_data.ptr(), p_data_size);8379}83808381void RenderingDevice::_compute_list_set_push_constant(ComputeListID p_list, const Vector<uint8_t> &p_data, uint32_t p_data_size) {8382ERR_FAIL_COND(p_data_size > (uint32_t)p_data.size());8383compute_list_set_push_constant(p_list, p_data.ptr(), p_data_size);8384}83858386static_assert(ENUM_MEMBERS_EQUAL(RD::CALLBACK_RESOURCE_USAGE_NONE, RDG::RESOURCE_USAGE_NONE));8387static_assert(ENUM_MEMBERS_EQUAL(RD::CALLBACK_RESOURCE_USAGE_COPY_FROM, RDG::RESOURCE_USAGE_COPY_FROM));8388static_assert(ENUM_MEMBERS_EQUAL(RD::CALLBACK_RESOURCE_USAGE_COPY_TO, RDG::RESOURCE_USAGE_COPY_TO));8389static_assert(ENUM_MEMBERS_EQUAL(RD::CALLBACK_RESOURCE_USAGE_RESOLVE_FROM, RDG::RESOURCE_USAGE_RESOLVE_FROM));8390static_assert(ENUM_MEMBERS_EQUAL(RD::CALLBACK_RESOURCE_USAGE_RESOLVE_TO, RDG::RESOURCE_USAGE_RESOLVE_TO));8391static_assert(ENUM_MEMBERS_EQUAL(RD::CALLBACK_RESOURCE_USAGE_UNIFORM_BUFFER_READ, RDG::RESOURCE_USAGE_UNIFORM_BUFFER_READ));8392static_assert(ENUM_MEMBERS_EQUAL(RD::CALLBACK_RESOURCE_USAGE_INDIRECT_BUFFER_READ, RDG::RESOURCE_USAGE_INDIRECT_BUFFER_READ));8393static_assert(ENUM_MEMBERS_EQUAL(RD::CALLBACK_RESOURCE_USAGE_TEXTURE_BUFFER_READ, RDG::RESOURCE_USAGE_TEXTURE_BUFFER_READ));8394static_assert(ENUM_MEMBERS_EQUAL(RD::CALLBACK_RESOURCE_USAGE_TEXTURE_BUFFER_READ_WRITE, RDG::RESOURCE_USAGE_TEXTURE_BUFFER_READ_WRITE));8395static_assert(ENUM_MEMBERS_EQUAL(RD::CALLBACK_RESOURCE_USAGE_STORAGE_BUFFER_READ, RDG::RESOURCE_USAGE_STORAGE_BUFFER_READ));8396static_assert(ENUM_MEMBERS_EQUAL(RD::CALLBACK_RESOURCE_USAGE_STORAGE_BUFFER_READ_WRITE, RDG::RESOURCE_USAGE_STORAGE_BUFFER_READ_WRITE));8397static_assert(ENUM_MEMBERS_EQUAL(RD::CALLBACK_RESOURCE_USAGE_VERTEX_BUFFER_READ, RDG::RESOURCE_USAGE_VERTEX_BUFFER_READ));8398static_assert(ENUM_MEMBERS_EQUAL(RD::CALLBACK_RESOURCE_USAGE_INDEX_BUFFER_READ, RDG::RESOURCE_USAGE_INDEX_BUFFER_READ));8399static_assert(ENUM_MEMBERS_EQUAL(RD::CALLBACK_RESOURCE_USAGE_TEXTURE_SAMPLE, RDG::RESOURCE_USAGE_TEXTURE_SAMPLE));8400static_assert(ENUM_MEMBERS_EQUAL(RD::CALLBACK_RESOURCE_USAGE_STORAGE_IMAGE_READ, RDG::RESOURCE_USAGE_STORAGE_IMAGE_READ));8401static_assert(ENUM_MEMBERS_EQUAL(RD::CALLBACK_RESOURCE_USAGE_STORAGE_IMAGE_READ_WRITE, RDG::RESOURCE_USAGE_STORAGE_IMAGE_READ_WRITE));8402static_assert(ENUM_MEMBERS_EQUAL(RD::CALLBACK_RESOURCE_USAGE_ATTACHMENT_COLOR_READ_WRITE, RDG::RESOURCE_USAGE_ATTACHMENT_COLOR_READ_WRITE));8403static_assert(ENUM_MEMBERS_EQUAL(RD::CALLBACK_RESOURCE_USAGE_ATTACHMENT_DEPTH_STENCIL_READ_WRITE, RDG::RESOURCE_USAGE_ATTACHMENT_DEPTH_STENCIL_READ_WRITE));8404static_assert(ENUM_MEMBERS_EQUAL(RD::CALLBACK_RESOURCE_USAGE_GENERAL, RDG::RESOURCE_USAGE_GENERAL));8405static_assert(ENUM_MEMBERS_EQUAL(RD::CALLBACK_RESOURCE_USAGE_MAX, RDG::RESOURCE_USAGE_MAX));840684078408