summaryrefslogtreecommitdiffstats
path: root/servers/rendering/rendering_device.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'servers/rendering/rendering_device.cpp')
-rw-r--r--servers/rendering/rendering_device.cpp354
1 files changed, 336 insertions, 18 deletions
diff --git a/servers/rendering/rendering_device.cpp b/servers/rendering/rendering_device.cpp
index 15e1731823..474fdb387f 100644
--- a/servers/rendering/rendering_device.cpp
+++ b/servers/rendering/rendering_device.cpp
@@ -824,8 +824,8 @@ RID RenderingDevice::texture_create(const TextureFormat &p_format, const Texture
}
if (texture.draw_tracker != nullptr) {
- // Draw tracker can assume the texture will be in transfer destination.
- texture.draw_tracker->usage = RDG::RESOURCE_USAGE_TRANSFER_TO;
+ // Draw tracker can assume the texture will be in copy destination.
+ texture.draw_tracker->usage = RDG::RESOURCE_USAGE_COPY_TO;
}
}
@@ -847,8 +847,11 @@ RID RenderingDevice::texture_create_shared(const TextureView &p_view, RID p_with
// Create view.
Texture texture = *src_texture;
+ texture.shared_fallback = nullptr;
RDD::TextureView tv;
+ bool create_shared = true;
+ bool raw_reintepretation = false;
if (p_view.format_override == DATA_FORMAT_MAX || p_view.format_override == texture.format) {
tv.format = texture.format;
} else {
@@ -857,13 +860,47 @@ RID RenderingDevice::texture_create_shared(const TextureView &p_view, RID p_with
ERR_FAIL_COND_V_MSG(!texture.allowed_shared_formats.has(p_view.format_override), RID(),
"Format override is not in the list of allowed shareable formats for original texture.");
tv.format = p_view.format_override;
+ create_shared = driver->texture_can_make_shared_with_format(texture.driver_id, p_view.format_override, raw_reintepretation);
}
tv.swizzle_r = p_view.swizzle_r;
tv.swizzle_g = p_view.swizzle_g;
tv.swizzle_b = p_view.swizzle_b;
tv.swizzle_a = p_view.swizzle_a;
- texture.driver_id = driver->texture_create_shared(texture.driver_id, tv);
+ if (create_shared) {
+ texture.driver_id = driver->texture_create_shared(texture.driver_id, tv);
+ } else {
+ // The regular view will use the same format as the main texture.
+ RDD::TextureView regular_view = tv;
+ regular_view.format = src_texture->format;
+ texture.driver_id = driver->texture_create_shared(texture.driver_id, regular_view);
+
+ // Create the independent texture for the alias.
+ RDD::TextureFormat alias_format = texture.texture_format();
+ alias_format.format = tv.format;
+ alias_format.usage_bits = TEXTURE_USAGE_SAMPLING_BIT | TEXTURE_USAGE_CAN_COPY_TO_BIT;
+
+ _texture_check_shared_fallback(src_texture);
+ _texture_check_shared_fallback(&texture);
+
+ texture.shared_fallback->texture = driver->texture_create(alias_format, tv);
+ texture.shared_fallback->raw_reinterpretation = raw_reintepretation;
+ texture_memory += driver->texture_get_allocation_size(texture.shared_fallback->texture);
+
+ RDG::ResourceTracker *tracker = RDG::resource_tracker_create();
+ tracker->texture_driver_id = texture.shared_fallback->texture;
+ tracker->texture_subresources = texture.barrier_range();
+ tracker->texture_usage = alias_format.usage_bits;
+ tracker->reference_count = 1;
+ texture.shared_fallback->texture_tracker = tracker;
+ texture.shared_fallback->revision = 0;
+
+ if (raw_reintepretation && src_texture->shared_fallback->buffer.id == 0) {
+ // For shared textures of the same size, we create the buffer on the main texture if it doesn't have it already.
+ _texture_create_reinterpret_buffer(src_texture);
+ }
+ }
+
ERR_FAIL_COND_V(!texture.driver_id, RID());
texture.slice_trackers.clear();
@@ -965,6 +1002,7 @@ RID RenderingDevice::texture_create_shared_from_slice(const TextureView &p_view,
}
Texture texture = *src_texture;
+ texture.shared_fallback = nullptr;
get_image_format_required_size(texture.format, texture.width, texture.height, texture.depth, p_mipmap + 1, &texture.width, &texture.height);
texture.mipmaps = p_mipmaps;
@@ -979,6 +1017,8 @@ RID RenderingDevice::texture_create_shared_from_slice(const TextureView &p_view,
}
RDD::TextureView tv;
+ bool create_shared = true;
+ bool raw_reintepretation = false;
if (p_view.format_override == DATA_FORMAT_MAX || p_view.format_override == texture.format) {
tv.format = texture.format;
} else {
@@ -987,7 +1027,9 @@ RID RenderingDevice::texture_create_shared_from_slice(const TextureView &p_view,
ERR_FAIL_COND_V_MSG(!texture.allowed_shared_formats.has(p_view.format_override), RID(),
"Format override is not in the list of allowed shareable formats for original texture.");
tv.format = p_view.format_override;
+ create_shared = driver->texture_can_make_shared_with_format(texture.driver_id, p_view.format_override, raw_reintepretation);
}
+
tv.swizzle_r = p_view.swizzle_r;
tv.swizzle_g = p_view.swizzle_g;
tv.swizzle_b = p_view.swizzle_b;
@@ -1000,7 +1042,47 @@ RID RenderingDevice::texture_create_shared_from_slice(const TextureView &p_view,
"Specified layer must be a multiple of 6.");
}
- texture.driver_id = driver->texture_create_shared_from_slice(src_texture->driver_id, tv, p_slice_type, p_layer, slice_layers, p_mipmap, p_mipmaps);
+ if (create_shared) {
+ texture.driver_id = driver->texture_create_shared_from_slice(src_texture->driver_id, tv, p_slice_type, p_layer, slice_layers, p_mipmap, p_mipmaps);
+ } else {
+ // The regular view will use the same format as the main texture.
+ RDD::TextureView regular_view = tv;
+ regular_view.format = src_texture->format;
+ texture.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);
+
+ // Create the independent texture for the slice.
+ RDD::TextureSubresourceRange slice_range = texture.barrier_range();
+ slice_range.base_mipmap = 0;
+ slice_range.base_layer = 0;
+
+ RDD::TextureFormat slice_format = texture.texture_format();
+ slice_format.width = MAX(texture.width >> p_mipmap, 1U);
+ slice_format.height = MAX(texture.height >> p_mipmap, 1U);
+ slice_format.depth = MAX(texture.depth >> p_mipmap, 1U);
+ slice_format.format = tv.format;
+ slice_format.usage_bits = TEXTURE_USAGE_SAMPLING_BIT | TEXTURE_USAGE_CAN_COPY_TO_BIT;
+
+ _texture_check_shared_fallback(src_texture);
+ _texture_check_shared_fallback(&texture);
+
+ texture.shared_fallback->texture = driver->texture_create(slice_format, tv);
+ texture.shared_fallback->raw_reinterpretation = raw_reintepretation;
+ texture_memory += driver->texture_get_allocation_size(texture.shared_fallback->texture);
+
+ RDG::ResourceTracker *tracker = RDG::resource_tracker_create();
+ tracker->texture_driver_id = texture.shared_fallback->texture;
+ tracker->texture_subresources = slice_range;
+ tracker->texture_usage = slice_format.usage_bits;
+ tracker->reference_count = 1;
+ texture.shared_fallback->texture_tracker = tracker;
+ texture.shared_fallback->revision = 0;
+
+ if (raw_reintepretation && src_texture->shared_fallback->buffer.id == 0) {
+ // For shared texture slices, we create the buffer on the slice if the source texture has no reinterpretation buffer.
+ _texture_create_reinterpret_buffer(&texture);
+ }
+ }
+
ERR_FAIL_COND_V(!texture.driver_id, RID());
const Rect2i slice_rect(p_mipmap, p_layer, p_mipmaps, slice_layers);
@@ -1093,15 +1175,18 @@ Error RenderingDevice::_texture_update(RID p_texture, uint32_t p_layer, const Ve
// When using the setup queue directly, we transition the texture to the optimal layout.
RDD::TextureBarrier tb;
tb.texture = texture->driver_id;
- tb.dst_access = RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT;
+ tb.dst_access = RDD::BARRIER_ACCESS_COPY_WRITE_BIT;
tb.prev_layout = RDD::TEXTURE_LAYOUT_UNDEFINED;
- tb.next_layout = RDD::TEXTURE_LAYOUT_TRANSFER_DST_OPTIMAL;
+ tb.next_layout = RDD::TEXTURE_LAYOUT_COPY_DST_OPTIMAL;
tb.subresources.aspect = texture->barrier_aspect_flags;
tb.subresources.mipmap_count = texture->mipmaps;
tb.subresources.base_layer = p_layer;
tb.subresources.layer_count = 1;
- driver->command_pipeline_barrier(frames[frame].setup_command_buffer, RDD::PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, RDD::PIPELINE_STAGE_TRANSFER_BIT, {}, {}, tb);
+ driver->command_pipeline_barrier(frames[frame].setup_command_buffer, RDD::PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, RDD::PIPELINE_STAGE_COPY_BIT, {}, {}, tb);
+ } else if (!p_use_setup_queue) {
+ // Indicate the texture will get modified for the shared texture fallback.
+ _texture_update_shared_fallback(p_texture, texture, true);
}
uint32_t mipmap_offset = 0;
@@ -1199,7 +1284,7 @@ Error RenderingDevice::_texture_update(RID p_texture, uint32_t p_layer, const Ve
copy_region.texture_region_size = Vector3i(region_logic_w, region_logic_h, 1);
if (p_use_setup_queue) {
- driver->command_copy_buffer_to_texture(frames[frame].setup_command_buffer, staging_buffer_blocks[staging_buffer_current].driver_id, texture->driver_id, RDD::TEXTURE_LAYOUT_TRANSFER_DST_OPTIMAL, copy_region);
+ driver->command_copy_buffer_to_texture(frames[frame].setup_command_buffer, staging_buffer_blocks[staging_buffer_current].driver_id, texture->driver_id, RDD::TEXTURE_LAYOUT_COPY_DST_OPTIMAL, copy_region);
} else {
RDG::RecordedBufferToTextureCopy buffer_to_texture_copy;
buffer_to_texture_copy.from_buffer = staging_buffer_blocks[staging_buffer_current].driver_id;
@@ -1221,14 +1306,14 @@ Error RenderingDevice::_texture_update(RID p_texture, uint32_t p_layer, const Ve
// If the texture does not have a tracker, it means it must be transitioned to the sampling state.
RDD::TextureBarrier tb;
tb.texture = texture->driver_id;
- tb.src_access = RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT;
- tb.prev_layout = RDD::TEXTURE_LAYOUT_TRANSFER_DST_OPTIMAL;
+ tb.src_access = RDD::BARRIER_ACCESS_COPY_WRITE_BIT;
+ tb.prev_layout = RDD::TEXTURE_LAYOUT_COPY_DST_OPTIMAL;
tb.next_layout = RDD::TEXTURE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
tb.subresources.aspect = texture->barrier_aspect_flags;
tb.subresources.mipmap_count = texture->mipmaps;
tb.subresources.base_layer = p_layer;
tb.subresources.layer_count = 1;
- driver->command_pipeline_barrier(frames[frame].setup_command_buffer, RDD::PIPELINE_STAGE_TRANSFER_BIT, RDD::PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, {}, {}, tb);
+ driver->command_pipeline_barrier(frames[frame].setup_command_buffer, RDD::PIPELINE_STAGE_COPY_BIT, RDD::PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, {}, {}, tb);
} else if (!p_use_setup_queue && !command_buffer_to_texture_copies_vector.is_empty()) {
if (_texture_make_mutable(texture, p_texture)) {
// The texture must be mutable to be used as a copy destination.
@@ -1241,6 +1326,186 @@ Error RenderingDevice::_texture_update(RID p_texture, uint32_t p_layer, const Ve
return OK;
}
+void RenderingDevice::_texture_check_shared_fallback(Texture *p_texture) {
+ if (p_texture->shared_fallback == nullptr) {
+ p_texture->shared_fallback = memnew(Texture::SharedFallback);
+ }
+}
+
+void RenderingDevice::_texture_update_shared_fallback(RID p_texture_rid, Texture *p_texture, bool p_for_writing) {
+ if (p_texture->shared_fallback == nullptr) {
+ // This texture does not use any of the shared texture fallbacks.
+ return;
+ }
+
+ if (p_texture->owner.is_valid()) {
+ Texture *owner_texture = texture_owner.get_or_null(p_texture->owner);
+ ERR_FAIL_NULL(owner_texture);
+ if (p_for_writing) {
+ // Only the main texture is used for writing when using the shared fallback.
+ owner_texture->shared_fallback->revision++;
+ } else if (p_texture->shared_fallback->revision != owner_texture->shared_fallback->revision) {
+ // Copy the contents of the main texture into the shared texture fallback slice. Update the revision.
+ _texture_copy_shared(p_texture->owner, owner_texture, p_texture_rid, p_texture);
+ p_texture->shared_fallback->revision = owner_texture->shared_fallback->revision;
+ }
+ } else if (p_for_writing) {
+ // Increment the revision of the texture so shared texture fallback slices must be updated.
+ p_texture->shared_fallback->revision++;
+ }
+}
+
+void RenderingDevice::_texture_free_shared_fallback(Texture *p_texture) {
+ if (p_texture->shared_fallback != nullptr) {
+ if (p_texture->shared_fallback->texture_tracker != nullptr) {
+ RDG::resource_tracker_free(p_texture->shared_fallback->texture_tracker);
+ }
+
+ if (p_texture->shared_fallback->buffer_tracker != nullptr) {
+ RDG::resource_tracker_free(p_texture->shared_fallback->buffer_tracker);
+ }
+
+ if (p_texture->shared_fallback->texture.id != 0) {
+ texture_memory -= driver->texture_get_allocation_size(p_texture->shared_fallback->texture);
+ driver->texture_free(p_texture->shared_fallback->texture);
+ }
+
+ if (p_texture->shared_fallback->buffer.id != 0) {
+ buffer_memory -= driver->buffer_get_allocation_size(p_texture->shared_fallback->buffer);
+ driver->buffer_free(p_texture->shared_fallback->buffer);
+ }
+
+ memdelete(p_texture->shared_fallback);
+ p_texture->shared_fallback = nullptr;
+ }
+}
+
+void RenderingDevice::_texture_copy_shared(RID p_src_texture_rid, Texture *p_src_texture, RID p_dst_texture_rid, Texture *p_dst_texture) {
+ // 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.
+ DEV_ASSERT(p_src_texture != nullptr);
+ DEV_ASSERT(p_dst_texture != nullptr);
+ DEV_ASSERT(p_src_texture->owner.is_null());
+ DEV_ASSERT(p_dst_texture->owner == p_src_texture_rid);
+
+ bool src_made_mutable = _texture_make_mutable(p_src_texture, p_src_texture_rid);
+ bool dst_made_mutable = _texture_make_mutable(p_dst_texture, p_dst_texture_rid);
+ if (src_made_mutable || dst_made_mutable) {
+ draw_graph.add_synchronization();
+ }
+
+ if (p_dst_texture->shared_fallback->raw_reinterpretation) {
+ // 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 hold
+ // anything and it's how the shared textures that don't use slices are created.
+ bool src_has_buffer = p_src_texture->shared_fallback->buffer.id != 0;
+ bool dst_has_buffer = p_dst_texture->shared_fallback->buffer.id != 0;
+ bool from_src = p_src_texture->owner.is_null() && src_has_buffer;
+ bool from_dst = p_dst_texture->owner.is_null() && dst_has_buffer;
+ if (!from_src && !from_dst) {
+ // If neither texture passed the condition, we just pick whichever texture has a reinterpretation buffer.
+ from_src = src_has_buffer;
+ from_dst = dst_has_buffer;
+ }
+
+ // Pick the buffer and tracker to use from the right texture.
+ RDD::BufferID shared_buffer;
+ RDG::ResourceTracker *shared_buffer_tracker = nullptr;
+ if (from_src) {
+ shared_buffer = p_src_texture->shared_fallback->buffer;
+ shared_buffer_tracker = p_src_texture->shared_fallback->buffer_tracker;
+ } else if (from_dst) {
+ shared_buffer = p_dst_texture->shared_fallback->buffer;
+ shared_buffer_tracker = p_dst_texture->shared_fallback->buffer_tracker;
+ } else {
+ DEV_ASSERT(false && "This path should not be reachable.");
+ }
+
+ // FIXME: When using reinterpretation buffers, the only texture aspect supported is color. Depth or stencil contents won't get copied.
+ RDD::BufferTextureCopyRegion get_data_region;
+ RDG::RecordedBufferToTextureCopy update_copy;
+ RDD::TextureCopyableLayout first_copyable_layout;
+ RDD::TextureCopyableLayout copyable_layout;
+ RDD::TextureSubresource texture_subresource;
+ texture_subresource.aspect = RDD::TEXTURE_ASPECT_COLOR;
+ texture_subresource.layer = 0;
+ texture_subresource.mipmap = 0;
+ driver->texture_get_copyable_layout(p_dst_texture->shared_fallback->texture, texture_subresource, &first_copyable_layout);
+
+ // Copying each mipmap from main texture to a buffer and then to the slice texture.
+ thread_local LocalVector<RDD::BufferTextureCopyRegion> get_data_vector;
+ thread_local LocalVector<RDG::RecordedBufferToTextureCopy> update_vector;
+ get_data_vector.clear();
+ update_vector.clear();
+ for (uint32_t i = 0; i < p_dst_texture->mipmaps; i++) {
+ driver->texture_get_copyable_layout(p_dst_texture->shared_fallback->texture, texture_subresource, &copyable_layout);
+
+ uint32_t mipmap = p_dst_texture->base_mipmap + i;
+ get_data_region.buffer_offset = copyable_layout.offset - first_copyable_layout.offset;
+ get_data_region.texture_subresources.aspect = RDD::TEXTURE_ASPECT_COLOR_BIT;
+ get_data_region.texture_subresources.base_layer = p_dst_texture->base_layer;
+ get_data_region.texture_subresources.mipmap = mipmap;
+ get_data_region.texture_subresources.layer_count = p_dst_texture->layers;
+ get_data_region.texture_region_size.x = MAX(1U, p_src_texture->width >> mipmap);
+ get_data_region.texture_region_size.y = MAX(1U, p_src_texture->height >> mipmap);
+ get_data_region.texture_region_size.z = MAX(1U, p_src_texture->depth >> mipmap);
+ get_data_vector.push_back(get_data_region);
+
+ update_copy.from_buffer = shared_buffer;
+ update_copy.region.buffer_offset = get_data_region.buffer_offset;
+ update_copy.region.texture_subresources.aspect = RDD::TEXTURE_ASPECT_COLOR_BIT;
+ update_copy.region.texture_subresources.base_layer = texture_subresource.layer;
+ update_copy.region.texture_subresources.mipmap = texture_subresource.mipmap;
+ update_copy.region.texture_subresources.layer_count = get_data_region.texture_subresources.layer_count;
+ update_copy.region.texture_region_size.x = get_data_region.texture_region_size.x;
+ update_copy.region.texture_region_size.y = get_data_region.texture_region_size.y;
+ update_copy.region.texture_region_size.z = get_data_region.texture_region_size.z;
+ update_vector.push_back(update_copy);
+
+ texture_subresource.mipmap++;
+ }
+
+ draw_graph.add_texture_get_data(p_src_texture->driver_id, p_src_texture->draw_tracker, shared_buffer, get_data_vector, shared_buffer_tracker);
+ draw_graph.add_texture_update(p_dst_texture->shared_fallback->texture, p_dst_texture->shared_fallback->texture_tracker, update_vector, shared_buffer_tracker);
+ } else {
+ // Raw reinterpretation is not required. Use a regular texture copy.
+ RDD::TextureCopyRegion copy_region;
+ copy_region.src_subresources.aspect = p_src_texture->read_aspect_flags;
+ copy_region.src_subresources.base_layer = p_dst_texture->base_layer;
+ copy_region.src_subresources.layer_count = p_dst_texture->layers;
+ copy_region.dst_subresources.aspect = p_dst_texture->read_aspect_flags;
+ copy_region.dst_subresources.base_layer = 0;
+ copy_region.dst_subresources.layer_count = copy_region.src_subresources.layer_count;
+
+ // Copying each mipmap from main texture to to the slice texture.
+ thread_local LocalVector<RDD::TextureCopyRegion> region_vector;
+ region_vector.clear();
+ for (uint32_t i = 0; i < p_dst_texture->mipmaps; i++) {
+ uint32_t mipmap = p_dst_texture->base_mipmap + i;
+ copy_region.src_subresources.mipmap = mipmap;
+ copy_region.dst_subresources.mipmap = i;
+ copy_region.size.x = MAX(1U, p_src_texture->width >> mipmap);
+ copy_region.size.y = MAX(1U, p_src_texture->height >> mipmap);
+ copy_region.size.z = MAX(1U, p_src_texture->depth >> mipmap);
+ region_vector.push_back(copy_region);
+ }
+
+ draw_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);
+ }
+}
+
+void RenderingDevice::_texture_create_reinterpret_buffer(Texture *p_texture) {
+ uint64_t row_pitch_step = driver->api_trait_get(RDD::API_TRAIT_TEXTURE_DATA_ROW_PITCH_STEP);
+ uint64_t transfer_alignment = driver->api_trait_get(RDD::API_TRAIT_TEXTURE_TRANSFER_ALIGNMENT);
+ uint32_t pixel_bytes = get_image_format_pixel_size(p_texture->format);
+ uint32_t row_pitch = STEPIFY(p_texture->width * pixel_bytes, row_pitch_step);
+ uint64_t buffer_size = STEPIFY(pixel_bytes * row_pitch * p_texture->height * p_texture->depth, transfer_alignment);
+ p_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);
+ buffer_memory += driver->buffer_get_allocation_size(p_texture->shared_fallback->buffer);
+
+ RDG::ResourceTracker *tracker = RDG::resource_tracker_create();
+ tracker->buffer_driver_id = p_texture->shared_fallback->buffer;
+ p_texture->shared_fallback->buffer_tracker = tracker;
+}
+
Vector<uint8_t> RenderingDevice::_texture_get_data(Texture *tex, uint32_t p_layer, bool p_2d) {
uint32_t width, height, depth;
uint32_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);
@@ -1535,6 +1800,9 @@ Error RenderingDevice::texture_copy(RID p_from_texture, RID p_to_texture, const
copy_region.size = p_size;
+ // Indicate the texture will get modified for the shared texture fallback.
+ _texture_update_shared_fallback(p_to_texture, dst_tex, true);
+
// The textures must be mutable to be used in the copy operation.
bool src_made_mutable = _texture_make_mutable(src_tex, p_from_texture);
bool dst_made_mutable = _texture_make_mutable(dst_tex, p_to_texture);
@@ -1578,6 +1846,9 @@ Error RenderingDevice::texture_resolve_multisample(RID p_from_texture, RID p_to_
ERR_FAIL_COND_V_MSG(src_tex->read_aspect_flags != dst_tex->read_aspect_flags, ERR_INVALID_PARAMETER,
"Source and destination texture must be of the same type (color or depth).");
+ // Indicate the texture will get modified for the shared texture fallback.
+ _texture_update_shared_fallback(p_to_texture, dst_tex, true);
+
// The textures must be mutable to be used in the resolve operation.
bool src_made_mutable = _texture_make_mutable(src_tex, p_from_texture);
bool dst_made_mutable = _texture_make_mutable(dst_tex, p_to_texture);
@@ -1620,6 +1891,9 @@ Error RenderingDevice::texture_clear(RID p_texture, const Color &p_color, uint32
range.base_layer = src_tex->base_layer + p_base_layer;
range.layer_count = p_layers;
+ // Indicate the texture will get modified for the shared texture fallback.
+ _texture_update_shared_fallback(p_texture, src_tex, true);
+
if (_texture_make_mutable(src_tex, p_texture)) {
// The texture must be mutable to be used as a clear destination.
draw_graph.add_synchronization();
@@ -2526,6 +2800,14 @@ RID RenderingDevice::uniform_buffer_create(uint32_t p_size_bytes, const Vector<u
return id;
}
+void RenderingDevice::_uniform_set_update_shared(UniformSet *p_uniform_set) {
+ for (UniformSet::SharedTexture shared : p_uniform_set->shared_textures_to_update) {
+ Texture *texture = texture_owner.get_or_null(shared.texture);
+ ERR_CONTINUE(texture == nullptr);
+ _texture_update_shared_fallback(shared.texture, texture, shared.writing);
+ }
+}
+
RID RenderingDevice::uniform_set_create(const Vector<Uniform> &p_uniforms, RID p_shader, uint32_t p_shader_set) {
_THREAD_SAFE_METHOD_
@@ -2554,6 +2836,7 @@ RID RenderingDevice::uniform_set_create(const Vector<Uniform> &p_uniforms, RID p
Vector<RDG::ResourceTracker *> draw_trackers;
Vector<RDG::ResourceUsage> draw_trackers_usage;
HashMap<RID, RDG::ResourceUsage> untracked_usage;
+ Vector<UniformSet::SharedTexture> shared_textures_to_update;
for (uint32_t i = 0; i < set_uniform_count; i++) {
const ShaderUniform &set_uniform = set_uniforms[i];
@@ -2619,8 +2902,16 @@ RID RenderingDevice::uniform_set_create(const Vector<Uniform> &p_uniforms, RID p
attachable_textures.push_back(attachable_texture);
}
- if (texture->draw_tracker != nullptr) {
- draw_trackers.push_back(texture->draw_tracker);
+ RDD::TextureID driver_id = texture->driver_id;
+ RDG::ResourceTracker *tracker = texture->draw_tracker;
+ if (texture->shared_fallback != nullptr && texture->shared_fallback->texture.id != 0) {
+ driver_id = texture->shared_fallback->texture;
+ tracker = texture->shared_fallback->texture_tracker;
+ shared_textures_to_update.push_back({ false, texture_id });
+ }
+
+ if (tracker != nullptr) {
+ draw_trackers.push_back(tracker);
draw_trackers_usage.push_back(RDG::RESOURCE_USAGE_TEXTURE_SAMPLE);
} else {
untracked_usage[texture_id] = RDG::RESOURCE_USAGE_TEXTURE_SAMPLE;
@@ -2629,7 +2920,7 @@ RID RenderingDevice::uniform_set_create(const Vector<Uniform> &p_uniforms, RID p
DEV_ASSERT(!texture->owner.is_valid() || texture_owner.get_or_null(texture->owner));
driver_uniform.ids.push_back(*sampler_driver_id);
- driver_uniform.ids.push_back(texture->driver_id);
+ driver_uniform.ids.push_back(driver_id);
}
} break;
case UNIFORM_TYPE_TEXTURE: {
@@ -2656,8 +2947,16 @@ RID RenderingDevice::uniform_set_create(const Vector<Uniform> &p_uniforms, RID p
attachable_textures.push_back(attachable_texture);
}
- if (texture->draw_tracker != nullptr) {
- draw_trackers.push_back(texture->draw_tracker);
+ RDD::TextureID driver_id = texture->driver_id;
+ RDG::ResourceTracker *tracker = texture->draw_tracker;
+ if (texture->shared_fallback != nullptr && texture->shared_fallback->texture.id != 0) {
+ driver_id = texture->shared_fallback->texture;
+ tracker = texture->shared_fallback->texture_tracker;
+ shared_textures_to_update.push_back({ false, texture_id });
+ }
+
+ if (tracker != nullptr) {
+ draw_trackers.push_back(tracker);
draw_trackers_usage.push_back(RDG::RESOURCE_USAGE_TEXTURE_SAMPLE);
} else {
untracked_usage[texture_id] = RDG::RESOURCE_USAGE_TEXTURE_SAMPLE;
@@ -2665,7 +2964,7 @@ RID RenderingDevice::uniform_set_create(const Vector<Uniform> &p_uniforms, RID p
DEV_ASSERT(!texture->owner.is_valid() || texture_owner.get_or_null(texture->owner));
- driver_uniform.ids.push_back(texture->driver_id);
+ driver_uniform.ids.push_back(driver_id);
}
} break;
case UNIFORM_TYPE_IMAGE: {
@@ -2687,6 +2986,10 @@ RID RenderingDevice::uniform_set_create(const Vector<Uniform> &p_uniforms, RID p
ERR_FAIL_COND_V_MSG(!(texture->usage_flags & TEXTURE_USAGE_STORAGE_BIT), RID(),
"Image (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") needs the TEXTURE_USAGE_STORAGE_BIT usage flag set in order to be used as uniform.");
+ if (texture->owner.is_null() && texture->shared_fallback != nullptr) {
+ shared_textures_to_update.push_back({ true, texture_id });
+ }
+
if (_texture_make_mutable(texture, texture_id)) {
// The texture must be mutable as a layout transition will be required.
draw_graph.add_synchronization();
@@ -2872,6 +3175,7 @@ RID RenderingDevice::uniform_set_create(const Vector<Uniform> &p_uniforms, RID p
uniform_set.draw_trackers = draw_trackers;
uniform_set.draw_trackers_usage = draw_trackers_usage;
uniform_set.untracked_usage = untracked_usage;
+ uniform_set.shared_textures_to_update = shared_textures_to_update;
uniform_set.shader_set = p_shader_set;
uniform_set.shader_id = p_shader;
@@ -3344,12 +3648,16 @@ Error RenderingDevice::_draw_list_render_pass_begin(Framebuffer *p_framebuffer,
for (int i = 0; i < p_framebuffer->texture_ids.size(); i++) {
RDD::RenderPassClearValue clear_value;
- Texture *texture = texture_owner.get_or_null(p_framebuffer->texture_ids[i]);
+ RID texture_rid = p_framebuffer->texture_ids[i];
+ Texture *texture = texture_owner.get_or_null(texture_rid);
if (!texture) {
color_index++;
continue;
}
+ // Indicate the texture will get modified for the shared texture fallback.
+ _texture_update_shared_fallback(texture_rid, texture, true);
+
if (texture->usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) {
if (color_index < p_clear_colors.size()) {
ERR_FAIL_INDEX_V(color_index, p_clear_colors.size(), ERR_BUG); // A bug.
@@ -3813,6 +4121,8 @@ void RenderingDevice::draw_list_draw(DrawListID p_list, bool p_use_indices, uint
draw_graph.add_draw_list_bind_uniform_set(dl->state.pipeline_shader_driver_id, dl->state.sets[i].uniform_set_driver_id, i);
UniformSet *uniform_set = uniform_set_owner.get_or_null(dl->state.sets[i].uniform_set);
+ _uniform_set_update_shared(uniform_set);
+
draw_graph.add_draw_list_usages(uniform_set->draw_trackers, uniform_set->draw_trackers_usage);
dl->state.sets[i].bound = true;
@@ -4219,6 +4529,8 @@ void RenderingDevice::compute_list_dispatch(ComputeListID p_list, uint32_t p_x_g
draw_graph.add_compute_list_bind_uniform_set(cl->state.pipeline_shader_driver_id, cl->state.sets[i].uniform_set_driver_id, i);
UniformSet *uniform_set = uniform_set_owner.get_or_null(cl->state.sets[i].uniform_set);
+ _uniform_set_update_shared(uniform_set);
+
draw_graph.add_compute_list_usages(uniform_set->draw_trackers, uniform_set->draw_trackers_usage);
cl->state.sets[i].bound = true;
@@ -4326,6 +4638,8 @@ void RenderingDevice::compute_list_dispatch_indirect(ComputeListID p_list, RID p
draw_graph.add_compute_list_bind_uniform_set(cl->state.pipeline_shader_driver_id, cl->state.sets[i].uniform_set_driver_id, i);
UniformSet *uniform_set = uniform_set_owner.get_or_null(cl->state.sets[i].uniform_set);
+ _uniform_set_update_shared(uniform_set);
+
draw_graph.add_compute_list_usages(uniform_set->draw_trackers, uniform_set->draw_trackers_usage);
cl->state.sets[i].bound = true;
@@ -4417,6 +4731,7 @@ bool RenderingDevice::_texture_make_mutable(Texture *p_texture, RID p_texture_id
draw_tracker->parent = owner_texture->draw_tracker;
draw_tracker->texture_driver_id = p_texture->driver_id;
draw_tracker->texture_subresources = p_texture->barrier_range();
+ draw_tracker->texture_usage = p_texture->usage_flags;
draw_tracker->texture_slice_or_dirty_rect = p_texture->slice_rect;
owner_texture->slice_trackers[p_texture->slice_rect] = draw_tracker;
}
@@ -4438,6 +4753,7 @@ bool RenderingDevice::_texture_make_mutable(Texture *p_texture, RID p_texture_id
p_texture->draw_tracker = RDG::resource_tracker_create();
p_texture->draw_tracker->texture_driver_id = p_texture->driver_id;
p_texture->draw_tracker->texture_subresources = p_texture->barrier_range();
+ p_texture->draw_tracker->texture_usage = p_texture->usage_flags;
p_texture->draw_tracker->reference_count = 1;
if (p_texture_id.is_valid()) {
@@ -4830,6 +5146,8 @@ void RenderingDevice::_free_pending_resources(int p_frame) {
WARN_PRINT("Deleted a texture while it was bound.");
}
+ _texture_free_shared_fallback(texture);
+
texture_memory -= driver->texture_get_allocation_size(texture->driver_id);
driver->texture_free(texture->driver_id);