diff --git a/drivers/vulkan/rendering_device_vulkan.cpp b/drivers/vulkan/rendering_device_vulkan.cpp index 42146cd7ec0..58569dc69e8 100644 --- a/drivers/vulkan/rendering_device_vulkan.cpp +++ b/drivers/vulkan/rendering_device_vulkan.cpp @@ -2294,7 +2294,7 @@ RID RenderingDeviceVulkan::texture_create_from_extension(TextureType p_type, Dat return id; } -RID RenderingDeviceVulkan::texture_create_shared_from_slice(const TextureView &p_view, RID p_with_texture, uint32_t p_layer, uint32_t p_mipmap, uint32_t p_mipmaps, TextureSliceType p_slice_type) { +RID RenderingDeviceVulkan::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) { _THREAD_SAFE_METHOD_ Texture *src_texture = texture_owner.get_or_null(p_with_texture); @@ -2322,7 +2322,11 @@ RID RenderingDeviceVulkan::texture_create_shared_from_slice(const TextureView &p ERR_FAIL_UNSIGNED_INDEX_V(p_layer, src_texture->layers, RID()); int slice_layers = 1; - if (p_slice_type == TEXTURE_SLICE_2D_ARRAY) { + if (p_layers != 0) { + ERR_FAIL_COND_V_MSG(p_layers > 1 && p_slice_type != TEXTURE_SLICE_2D_ARRAY, RID(), "layer slicing only supported for 2D arrays"); + ERR_FAIL_COND_V_MSG(p_layer + p_layers > src_texture->layers, RID(), "layer slice is out of bounds"); + slice_layers = p_layers; + } else if (p_slice_type == TEXTURE_SLICE_2D_ARRAY) { ERR_FAIL_COND_V_MSG(p_layer != 0, RID(), "layer must be 0 when obtaining a 2D array mipmap slice"); slice_layers = src_texture->layers; } else if (p_slice_type == TEXTURE_SLICE_CUBEMAP) { diff --git a/drivers/vulkan/rendering_device_vulkan.h b/drivers/vulkan/rendering_device_vulkan.h index b2c2a03a872..63c6b975157 100644 --- a/drivers/vulkan/rendering_device_vulkan.h +++ b/drivers/vulkan/rendering_device_vulkan.h @@ -1047,7 +1047,7 @@ public: virtual RID texture_create_shared(const TextureView &p_view, RID p_with_texture); virtual RID texture_create_from_extension(TextureType p_type, DataFormat p_format, TextureSamples p_samples, uint64_t p_flags, uint64_t p_image, uint64_t p_width, uint64_t p_height, uint64_t p_depth, uint64_t p_layers); - virtual RID 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 = 1, TextureSliceType p_slice_type = TEXTURE_SLICE_2D); + virtual RID 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 = 1, TextureSliceType p_slice_type = TEXTURE_SLICE_2D, uint32_t p_layers = 0); virtual Error texture_update(RID p_texture, uint32_t p_layer, const Vector &p_data, BitField p_post_barrier = BARRIER_MASK_ALL_BARRIERS); virtual Vector texture_get_data(RID p_texture, uint32_t p_layer); diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp index 885ea181512..5776414b14d 100644 --- a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp @@ -280,7 +280,7 @@ void RendererSceneRenderRD::_render_buffers_copy_screen_texture(const RenderData for (int i = 1; i < mipmaps; i++) { RID source = dest; dest = rb->get_texture_slice(RB_SCOPE_BUFFERS, RB_TEX_BLUR_0, v, i); - Size2i msize = rb->get_texture_slice_size(RB_SCOPE_BUFFERS, RB_TEX_BLUR_0, v, i); + Size2i msize = rb->get_texture_slice_size(RB_SCOPE_BUFFERS, RB_TEX_BLUR_0, i); if (can_use_storage) { copy_effects->make_mipmap(source, dest, msize); @@ -448,7 +448,7 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende float luminance_multiplier = _render_buffers_get_luminance_multiplier(); for (uint32_t l = 0; l < rb->get_view_count(); l++) { for (int i = 0; i < (max_glow_level + 1); i++) { - Size2i vp_size = rb->get_texture_slice_size(RB_SCOPE_BUFFERS, RB_TEX_BLUR_1, l, i); + Size2i vp_size = rb->get_texture_slice_size(RB_SCOPE_BUFFERS, RB_TEX_BLUR_1, i); if (i == 0) { RID luminance_texture; @@ -502,7 +502,7 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende tonemap.glow_levels[i] = environment_get_glow_levels(p_render_data->environment)[i]; } - Size2i msize = rb->get_texture_slice_size(RB_SCOPE_BUFFERS, RB_TEX_BLUR_1, 0, 0); + Size2i msize = rb->get_texture_slice_size(RB_SCOPE_BUFFERS, RB_TEX_BLUR_1, 0); tonemap.glow_texture_size.x = msize.width; tonemap.glow_texture_size.y = msize.height; tonemap.glow_use_bicubic_upscale = glow_bicubic_upscale; diff --git a/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp b/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp index 255719183fd..f5d6404f012 100644 --- a/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp +++ b/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp @@ -50,25 +50,19 @@ void RenderSceneBuffersRD::_bind_methods() { // ClassDB::bind_method(D_METHOD("create_texture_view", "context", "name", "view_name", "view"), &RenderSceneBuffersRD::has_texture); ClassDB::bind_method(D_METHOD("get_texture", "context", "name"), &RenderSceneBuffersRD::get_texture); // ClassDB::bind_method(D_METHOD("get_texture_format", "context", "name"), &RenderSceneBuffersRD::get_texture_format); - ClassDB::bind_method(D_METHOD("get_texture_slice", "context", "name", "layer", "mipmap"), &RenderSceneBuffersRD::get_texture_slice); - ClassDB::bind_method(D_METHOD("get_texture_slice_size", "context", "name", "layer", "mipmap"), &RenderSceneBuffersRD::get_texture_slice_size); + ClassDB::bind_method(D_METHOD("get_texture_slice", "context", "name", "layer", "mipmap", "layers", "mipmaps"), &RenderSceneBuffersRD::get_texture_slice); + ClassDB::bind_method(D_METHOD("get_texture_slice_size", "context", "name", "mipmap"), &RenderSceneBuffersRD::get_texture_slice_size); ClassDB::bind_method(D_METHOD("clear_context", "context"), &RenderSceneBuffersRD::clear_context); } void RenderSceneBuffersRD::update_sizes(NamedTexture &p_named_texture) { ERR_FAIL_COND(p_named_texture.texture.is_null()); - uint32_t size = p_named_texture.format.array_layers * p_named_texture.format.mipmaps; - p_named_texture.sizes.resize(size); + p_named_texture.sizes.resize(p_named_texture.format.mipmaps); Size2i mipmap_size = Size2i(p_named_texture.format.width, p_named_texture.format.height); - for (uint32_t mipmap = 0; mipmap < p_named_texture.format.mipmaps; mipmap++) { - for (uint32_t layer = 0; layer < p_named_texture.format.array_layers; layer++) { - uint32_t index = layer * p_named_texture.format.mipmaps + mipmap; - - p_named_texture.sizes.ptrw()[index] = mipmap_size; - } + p_named_texture.sizes.ptrw()[mipmap] = mipmap_size; mipmap_size.width = MAX(1, mipmap_size.width >> 1); mipmap_size.height = MAX(1, mipmap_size.height >> 1); @@ -324,7 +318,7 @@ const RD::TextureFormat RenderSceneBuffersRD::get_texture_format(const StringNam return named_textures[key].format; } -RID RenderSceneBuffersRD::get_texture_slice(const StringName &p_context, const StringName &p_texture_name, const uint32_t p_layer, const uint32_t p_mipmap) { +RID RenderSceneBuffersRD::get_texture_slice(const StringName &p_context, const StringName &p_texture_name, const uint32_t p_layer, const uint32_t p_mipmap, const uint32_t p_layers, const uint32_t p_mipmaps) { NTKey key(p_context, p_texture_name); // check if this is a known texture @@ -334,36 +328,41 @@ RID RenderSceneBuffersRD::get_texture_slice(const StringName &p_context, const S // check if we're in bounds ERR_FAIL_UNSIGNED_INDEX_V(p_layer, named_texture.format.array_layers, RID()); + ERR_FAIL_COND_V(p_layers == 0, RID()); + ERR_FAIL_COND_V(p_layer + p_layers > named_texture.format.array_layers, RID()); ERR_FAIL_UNSIGNED_INDEX_V(p_mipmap, named_texture.format.mipmaps, RID()); + ERR_FAIL_COND_V(p_mipmaps == 0, RID()); + ERR_FAIL_COND_V(p_mipmap + p_mipmaps > named_texture.format.mipmaps, RID()); - // if we don't have multiple layers or mipmaps, we can just return our texture as is - if (named_texture.format.array_layers == 1 && named_texture.format.mipmaps == 1) { + // asking the whole thing? just return the original + if (p_layer == 0 && p_mipmap == 0 && named_texture.format.array_layers == p_layers && named_texture.format.mipmaps == p_mipmaps) { return named_texture.texture; } - // get our index and make sure we have enough entries in our slices vector - uint32_t index = p_layer * named_texture.format.mipmaps + p_mipmap; - while (named_texture.slices.size() <= int(index)) { - named_texture.slices.push_back(RID()); + // see if we have this + NTSliceKey slice_key(p_layer, p_layers, p_mipmap, p_mipmaps); + if (named_texture.slices.has(slice_key)) { + return named_texture.slices[slice_key]; } - // create our slice if we don't have it already - if (named_texture.slices[index].is_null()) { - named_texture.slices.ptrw()[index] = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), named_texture.texture, p_layer, p_mipmap); + // create our slice + RID &slice = named_texture.slices[slice_key]; + slice = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), named_texture.texture, p_layer, p_mipmap, p_mipmaps, p_layers > 1 ? RD::TEXTURE_SLICE_2D_ARRAY : RD::TEXTURE_SLICE_2D, p_layers); - Array arr; - arr.push_back(p_context); - arr.push_back(p_texture_name); - arr.push_back(itos(p_layer)); - arr.push_back(itos(p_mipmap)); - RD::get_singleton()->set_resource_name(named_texture.slices[index], String("RenderBuffer {0}/{1} slice {2}/{3}").format(arr)); - } + Array arr; + arr.push_back(p_context); + arr.push_back(p_texture_name); + arr.push_back(itos(p_layer)); + arr.push_back(itos(p_layers)); + arr.push_back(itos(p_mipmap)); + arr.push_back(itos(p_mipmaps)); + RD::get_singleton()->set_resource_name(slice, String("RenderBuffer {0}/{1}, layer {2}/{3}, mipmap {4}/{5}").format(arr)); // and return our slice - return named_texture.slices[index]; + return slice; } -Size2i RenderSceneBuffersRD::get_texture_slice_size(const StringName &p_context, const StringName &p_texture_name, const uint32_t p_layer, const uint32_t p_mipmap) { +Size2i RenderSceneBuffersRD::get_texture_slice_size(const StringName &p_context, const StringName &p_texture_name, const uint32_t p_mipmap) { NTKey key(p_context, p_texture_name); // check if this is a known texture @@ -372,14 +371,10 @@ Size2i RenderSceneBuffersRD::get_texture_slice_size(const StringName &p_context, ERR_FAIL_COND_V(named_texture.texture.is_null(), Size2i()); // check if we're in bounds - ERR_FAIL_UNSIGNED_INDEX_V(p_layer, named_texture.format.array_layers, Size2i()); ERR_FAIL_UNSIGNED_INDEX_V(p_mipmap, named_texture.format.mipmaps, Size2i()); - // get our index - uint32_t index = p_layer * named_texture.format.mipmaps + p_mipmap; - - // and return our size - return named_texture.sizes[index]; + // return our size + return named_texture.sizes[p_mipmap]; } void RenderSceneBuffersRD::clear_context(const StringName &p_context) { diff --git a/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h b/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h index 50fb06c0d96..9a299a34157 100644 --- a/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h +++ b/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h @@ -93,7 +93,6 @@ private: } static uint32_t hash(const NTKey &p_val) { - // FIXME, properly hash two stringnames together uint32_t h = p_val.context.hash(); h = hash_murmur3_one_32(p_val.buffer_name.hash(), h); return hash_fmix32(h); @@ -106,6 +105,33 @@ private: } }; + struct NTSliceKey { + uint32_t layer; + uint32_t layers; + uint32_t mipmap; + uint32_t mipmaps; + + bool operator==(const NTSliceKey &p_val) const { + return (layer == p_val.layer) && (layers == p_val.layers) && (mipmap == p_val.mipmap) && (mipmaps == p_val.mipmaps); + } + + static uint32_t hash(const NTSliceKey &p_val) { + uint32_t h = hash_murmur3_one_32(p_val.layer); + h = hash_murmur3_one_32(p_val.layers, h); + h = hash_murmur3_one_32(p_val.mipmap, h); + h = hash_murmur3_one_32(p_val.mipmaps, h); + return hash_fmix32(h); + } + + NTSliceKey() {} + NTSliceKey(uint32_t p_layer, uint32_t p_layers, uint32_t p_mipmap, uint32_t p_mipmaps) { + layer = p_layer; + layers = p_layers; + mipmap = p_mipmap; + mipmaps = p_mipmaps; + } + }; + struct NamedTexture { // Cache the data used to create our texture RD::TextureFormat format; @@ -113,7 +139,7 @@ private: // Our texture objects, slices are lazy (i.e. only created when requested). RID texture; - Vector slices; + mutable HashMap slices; Vector sizes; }; @@ -154,8 +180,8 @@ public: RID create_texture_view(const StringName &p_context, const StringName &p_texture_name, const StringName p_view_name, RD::TextureView p_view = RD::TextureView()); RID get_texture(const StringName &p_context, const StringName &p_texture_name) const; const RD::TextureFormat get_texture_format(const StringName &p_context, const StringName &p_texture_name) const; - RID get_texture_slice(const StringName &p_context, const StringName &p_texture_name, const uint32_t p_layer, const uint32_t p_mipmap); - Size2i get_texture_slice_size(const StringName &p_context, const StringName &p_texture_name, const uint32_t p_layer, const uint32_t p_mipmap); + RID get_texture_slice(const StringName &p_context, const StringName &p_texture_name, const uint32_t p_layer, const uint32_t p_mipmap, const uint32_t p_layers = 1, const uint32_t p_mipmaps = 1); + Size2i get_texture_slice_size(const StringName &p_context, const StringName &p_texture_name, const uint32_t p_mipmap); void clear_context(const StringName &p_context); diff --git a/servers/rendering/rendering_device.h b/servers/rendering/rendering_device.h index 08ca25b64b0..91176691244 100644 --- a/servers/rendering/rendering_device.h +++ b/servers/rendering/rendering_device.h @@ -530,7 +530,7 @@ public: TEXTURE_SLICE_2D_ARRAY, }; - virtual RID 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 = 1, TextureSliceType p_slice_type = TEXTURE_SLICE_2D) = 0; + virtual RID 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 = 1, TextureSliceType p_slice_type = TEXTURE_SLICE_2D, uint32_t p_layers = 0) = 0; virtual Error texture_update(RID p_texture, uint32_t p_layer, const Vector &p_data, BitField p_post_barrier = BARRIER_MASK_ALL_BARRIERS) = 0; virtual Vector texture_get_data(RID p_texture, uint32_t p_layer) = 0; // CPU textures will return immediately, while GPU textures will most likely force a flush