Browse Source

Add layer slice support to render device and render buffers

Bastiaan Olij 2 years ago
parent
commit
093289364f

+ 6 - 2
drivers/vulkan/rendering_device_vulkan.cpp

@@ -2294,7 +2294,7 @@ RID RenderingDeviceVulkan::texture_create_from_extension(TextureType p_type, Dat
 	return id;
 	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_
 	_THREAD_SAFE_METHOD_
 
 
 	Texture *src_texture = texture_owner.get_or_null(p_with_texture);
 	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());
 	ERR_FAIL_UNSIGNED_INDEX_V(p_layer, src_texture->layers, RID());
 
 
 	int slice_layers = 1;
 	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");
 		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;
 		slice_layers = src_texture->layers;
 	} else if (p_slice_type == TEXTURE_SLICE_CUBEMAP) {
 	} else if (p_slice_type == TEXTURE_SLICE_CUBEMAP) {

+ 1 - 1
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_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_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<uint8_t> &p_data, BitField<BarrierMask> p_post_barrier = BARRIER_MASK_ALL_BARRIERS);
 	virtual Error texture_update(RID p_texture, uint32_t p_layer, const Vector<uint8_t> &p_data, BitField<BarrierMask> p_post_barrier = BARRIER_MASK_ALL_BARRIERS);
 	virtual Vector<uint8_t> texture_get_data(RID p_texture, uint32_t p_layer);
 	virtual Vector<uint8_t> texture_get_data(RID p_texture, uint32_t p_layer);
 
 

+ 3 - 3
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++) {
 		for (int i = 1; i < mipmaps; i++) {
 			RID source = dest;
 			RID source = dest;
 			dest = rb->get_texture_slice(RB_SCOPE_BUFFERS, RB_TEX_BLUR_0, v, i);
 			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) {
 			if (can_use_storage) {
 				copy_effects->make_mipmap(source, dest, msize);
 				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();
 		float luminance_multiplier = _render_buffers_get_luminance_multiplier();
 		for (uint32_t l = 0; l < rb->get_view_count(); l++) {
 		for (uint32_t l = 0; l < rb->get_view_count(); l++) {
 			for (int i = 0; i < (max_glow_level + 1); i++) {
 			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) {
 				if (i == 0) {
 					RID luminance_texture;
 					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];
 				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.x = msize.width;
 			tonemap.glow_texture_size.y = msize.height;
 			tonemap.glow_texture_size.y = msize.height;
 			tonemap.glow_use_bicubic_upscale = glow_bicubic_upscale;
 			tonemap.glow_use_bicubic_upscale = glow_bicubic_upscale;

+ 30 - 35
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("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", "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_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);
 	ClassDB::bind_method(D_METHOD("clear_context", "context"), &RenderSceneBuffersRD::clear_context);
 }
 }
 
 
 void RenderSceneBuffersRD::update_sizes(NamedTexture &p_named_texture) {
 void RenderSceneBuffersRD::update_sizes(NamedTexture &p_named_texture) {
 	ERR_FAIL_COND(p_named_texture.texture.is_null());
 	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);
 	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 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.width = MAX(1, mipmap_size.width >> 1);
 		mipmap_size.height = MAX(1, mipmap_size.height >> 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;
 	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);
 	NTKey key(p_context, p_texture_name);
 
 
 	// check if this is a known texture
 	// 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
 	// check if we're in bounds
 	ERR_FAIL_UNSIGNED_INDEX_V(p_layer, named_texture.format.array_layers, RID());
 	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_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;
 		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
 	// 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);
 	NTKey key(p_context, p_texture_name);
 
 
 	// check if this is a known texture
 	// 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());
 	ERR_FAIL_COND_V(named_texture.texture.is_null(), Size2i());
 
 
 	// check if we're in bounds
 	// 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());
 	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) {
 void RenderSceneBuffersRD::clear_context(const StringName &p_context) {

+ 30 - 4
servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h

@@ -93,7 +93,6 @@ private:
 		}
 		}
 
 
 		static uint32_t hash(const NTKey &p_val) {
 		static uint32_t hash(const NTKey &p_val) {
-			// FIXME, properly hash two stringnames together
 			uint32_t h = p_val.context.hash();
 			uint32_t h = p_val.context.hash();
 			h = hash_murmur3_one_32(p_val.buffer_name.hash(), h);
 			h = hash_murmur3_one_32(p_val.buffer_name.hash(), h);
 			return hash_fmix32(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 {
 	struct NamedTexture {
 		// Cache the data used to create our texture
 		// Cache the data used to create our texture
 		RD::TextureFormat format;
 		RD::TextureFormat format;
@@ -113,7 +139,7 @@ private:
 
 
 		// Our texture objects, slices are lazy (i.e. only created when requested).
 		// Our texture objects, slices are lazy (i.e. only created when requested).
 		RID texture;
 		RID texture;
-		Vector<RID> slices;
+		mutable HashMap<NTSliceKey, RID, NTSliceKey> slices;
 		Vector<Size2i> sizes;
 		Vector<Size2i> 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 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;
 	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;
 	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);
 	void clear_context(const StringName &p_context);
 
 

+ 1 - 1
servers/rendering/rendering_device.h

@@ -530,7 +530,7 @@ public:
 		TEXTURE_SLICE_2D_ARRAY,
 		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<uint8_t> &p_data, BitField<BarrierMask> p_post_barrier = BARRIER_MASK_ALL_BARRIERS) = 0;
 	virtual Error texture_update(RID p_texture, uint32_t p_layer, const Vector<uint8_t> &p_data, BitField<BarrierMask> p_post_barrier = BARRIER_MASK_ALL_BARRIERS) = 0;
 	virtual Vector<uint8_t> 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
 	virtual Vector<uint8_t> 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