How can you verify dependencies are actually used?

Hi,
new to this forum need some help about this, the topic could be condensed in “Rendering into a texture in one render pass that then another - different - render pass uses to sample”.

I am re-posting this from another place, hope can get some better answers here, thanks in advance for help :slight_smile:

Hi, ok this may sound a silly question but “how can you be sure dependencies are doing what you think should be doing ?” I am having this very simple bit of code that runs a shader and renders in a texture, then another one that gets it and use to map in on a cube. Let’s say it works, with my FB with dependencies defined as this :

dependencies[0].srcSubpass = VK_SUBPASS_EXTERNAL;
dependencies[0].dstSubpass = 0;
dependencies[0].srcStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
dependencies[0].dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dependencies[0].srcAccessMask = VK_ACCESS_SHADER_READ_BIT;
dependencies[0].dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
dependencies[0].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;

dependencies[2].srcSubpass = 0;
dependencies[2].dstSubpass = VK_SUBPASS_EXTERNAL;
dependencies[2].srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dependencies[2].dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
dependencies[2].srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
dependencies[2].dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
dependencies[2].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;


dependencies[1].srcSubpass = VK_SUBPASS_EXTERNAL;
dependencies[1].dstSubpass = 0;
dependencies[1].srcStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
dependencies[1].dstStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
dependencies[1].srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
dependencies[1].dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT;
dependencies[1].dependencyFlags = 0;

And then later on :

rp_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
rp_info.pNext = NULL;
rp_info.flags = 0;
rp_info.attachmentCount = a_index+1; //  2;
rp_info.pAttachments = attachments;
rp_info.subpassCount = 1;
rp_info.pSubpasses = &subpass;
rp_info.dependencyCount = 3; // 2
rp_info.pDependencies = dependencies;

result = vkCreateRenderPass(DeviceParams.device, &rp_info, NULL, rp);
assert(result == VK_SUCCESS);

And yes … it appears to work … but it seems to be working the same even if I change it into :

rp_info.dependencyCount = 0;
rp_info.pDependencies = NULL;

result = vkCreateRenderPass(DeviceParams.device, &rp_info, NULL, rp);
assert(result == VK_SUCCESS);

With no visual artifacts whatsoever … So hum … “how can I be sure it’s doing what it should be doing ?”

Thanks in advance for any reply.

Turn on validation layers. You shouldn’t be writing Vulkan code without using them.

It’s also unclear what those dependencies are expected to actually do for you. Specifically, dependencies 0 and 1 seem to be trying to say the same thing, so why are they separate? There’s basically no reason to have two external source dependencies to the same internal subpass.

Hi,
I am relatively new to Vulkan, is only a month and a half I am working with it trying to learn it from a book ( really ) and samples an such and all I can find.

I was wondering as well, why ‘0’ too ? I did try that from this code I found online ( the only sample I could find ) :

Example I found

Yes so far I am using validation layers all time, in fact while I was doing/experimenting with this I got many error messages about my barriers/dependencies not being correct ( I was also trying to ditch the dependencies an set a vkImageBarrier but again I could not really figure out what I was doing wrong ).

My understanding is that the dependency at ‘2’ should be sufficient with the one I put at ‘1’ for the z-buffer itself.

What puzzles me is that even if I don’t put any dependencies at all I’d expect to see “lot of garbage” happening while I am sampling the texture in the other render pass but I don’t, so this confuses me as I am not sure if I am doing the correct thing or not.

[edit] - in fact I just removed that one at ‘0’ and left only ‘2’ and ‘1’ and still seems to work ok, I don’t want to put here all the validators output because it’s too long but I can’t see any errors or such in it.

Actually sorry, I think if I am correctly understanding the dependencies should be like this ?

	dependencies[0].srcSubpass = 0;
	dependencies[0].dstSubpass = VK_SUBPASS_EXTERNAL;
	dependencies[0].srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
	dependencies[0].dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
	dependencies[0].srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
	dependencies[0].dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
	dependencies[0].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
	

	dependencies[1].srcSubpass = 0;
	dependencies[1].dstSubpass = VK_SUBPASS_EXTERNAL;
	dependencies[1].srcStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
	dependencies[1].dstStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
	dependencies[1].srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
	dependencies[1].dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT;
	dependencies[1].dependencyFlags = 0;

Which IF I am understand correctly, for example the one at ‘0’ says :

“The source renderpass is this same, the destination is something else”, the src is color attachemenr being written and the destination is a fragment shader being read.

Which means it should lock until a color been written in the color attachment if a fragment shader is trying to do a read from it ?

Am I “reading” this with the correct meaning or I am reading it wrong ?

Again, what do your validation layers say when you do that? A validation layer failure should not be seen as ignorable.

In Vulkan, just because something appears to work does not mean that it actually does work. That’s why we have validation layers.

Ok … this is the output from the validators, in pieces :

Initialization of a few things :

INFO: (DESCRIPTOR_POOL 0x7f) [Validation]  [ UNASSIGNED-ObjectTracker-Info ] Object: 0x7f (Type = 22) | OBJ[0x8e] : CREATE DescriptorPool object 0x7f
LSRenderer :: Init allocated Desc Pool OK !
LS_CreateRenderer : renderer initialized
You don't own the INIT CMD

Initialization of the ‘scene’ that contains the “offscreen renderpass” …

Toyscene INITSCENE called
ShaderToy_0_Scene::CreateUniformsBuffers : size 64
INFO: (BUFFER 0x80) [Validation]  [ UNASSIGNED-ObjectTracker-Info ] Object: 0x80 (Type = 9) | OBJ[0x8f] : CREATE Buffer object 0x80
INFO: (DEVICE_MEMORY 0x81) [Validation]  [ UNASSIGNED-ObjectTracker-Info ] Object: 0x81 (Type = 8) | OBJ[0x90] : CREATE DeviceMemory object 0x81
INFO: (BUFFER 0x82) [Validation]  [ UNASSIGNED-ObjectTracker-Info ] Object: 0x82 (Type = 9) | OBJ[0x91] : CREATE Buffer object 0x82
INFO: (DEVICE_MEMORY 0x83) [Validation]  [ UNASSIGNED-ObjectTracker-Info ] Object: 0x83 (Type = 8) | OBJ[0x92] : CREATE DeviceMemory object 0x83
INFO: (BUFFER 0x84) [Validation]  [ UNASSIGNED-ObjectTracker-Info ] Object: 0x84 (Type = 9) | OBJ[0x93] : CREATE Buffer object 0x84
INFO: (DEVICE_MEMORY 0x85) [Validation]  [ UNASSIGNED-ObjectTracker-Info ] Object: 0x85 (Type = 8) | OBJ[0x94] : CREATE DeviceMemory object 0x85
INFO: (BUFFER 0x86) [Validation]  [ UNASSIGNED-ObjectTracker-Info ] Object: 0x86 (Type = 9) | OBJ[0x95] : CREATE Buffer object 0x86
INFO: (DEVICE_MEMORY 0x87) [Validation]  [ UNASSIGNED-ObjectTracker-Info ] Object: 0x87 (Type = 8) | OBJ[0x96] : CREATE DeviceMemory object 0x87
Binding 0 , Location 0,  0
Binding 0 , Location 1,  16
Binding 0 , Location 2,  32
Single element size 40, total size 240
INFO: (BUFFER 0x88) [Validation]  [ UNASSIGNED-ObjectTracker-Info ] Object: 0x88 (Type = 9) | OBJ[0x97] : CREATE Buffer object 0x88
INFO: (DEVICE_MEMORY 0x89) [Validation]  [ UNASSIGNED-ObjectTracker-Info ] Object: 0x89 (Type = 8) | OBJ[0x98] : CREATE DeviceMemory object 0x89
Toyscene, texture opened OK

Shaders are created ( vertex / fragment )

INFO: (SHADER_MODULE 0x8a) [Validation]  [ UNASSIGNED-ObjectTracker-Info ] Object: 0x8a (Type = 15) | OBJ[0x99] : CREATE ShaderModule object 0x8a
INFO: (SHADER_MODULE 0x8b) [Validation]  [ UNASSIGNED-ObjectTracker-Info ] Object: 0x8b (Type = 15) | OBJ[0x9a] : CREATE ShaderModule object 0x8b
Toyscene : shaders all OK

One sampler is crated

INFO: (SAMPLER 0x8c) [Validation]  [ UNASSIGNED-ObjectTracker-Info ] Object: 0x8c (Type = 21) | OBJ[0x9b] : CREATE Sampler object 0x8c
INFO: (IMAGE 0x8d) [Validation]  [ UNASSIGNED-ObjectTracker-Info ] Object: 0x8d (Type = 10) | OBJ[0x9c] : CREATE Image object 0x8d
INFO: (DEVICE_MEMORY 0x8e) [Validation]  [ UNASSIGNED-ObjectTracker-Info ] Object: 0x8e (Type = 8) | OBJ[0x9d] : CREATE DeviceMemory object 0x8e

There’s alredy a sampler set !

INFO: (IMAGE_VIEW 0x8f) [Validation]  [ UNASSIGNED-ObjectTracker-Info ] Object: 0x8f (Type = 14) | OBJ[0x9e] : CREATE ImageView object 0x8f

Toyscene : Offscreen texture creation

INFO: (IMAGE 0x90) [Validation]  [ UNASSIGNED-ObjectTracker-Info ] Object: 0x90 (Type = 10) | OBJ[0x9f] : CREATE Image object 0x90
INFO: (DEVICE_MEMORY 0x91) [Validation]  [ UNASSIGNED-ObjectTracker-Info ] Object: 0x91 (Type = 8) | OBJ[0xa0] : CREATE DeviceMemory object 0x91
INFO: (SAMPLER 0x92) [Validation]  [ UNASSIGNED-ObjectTracker-Info ] Object: 0x92 (Type = 21) | OBJ[0xa1] : CREATE Sampler object 0x92
INFO: (IMAGE_VIEW 0x93) [Validation]  [ UNASSIGNED-ObjectTracker-Info ] Object: 0x93 (Type = 14) | OBJ[0xa2] : CREATE ImageView object 0x93
INFO: (IMAGE 0x94) [Validation]  [ UNASSIGNED-ObjectTracker-Info ] Object: 0x94 (Type = 10) | OBJ[0xa3] : CREATE Image object 0x94
INFO: (DEVICE_MEMORY 0x95) [Validation]  [ UNASSIGNED-ObjectTracker-Info ] Object: 0x95 (Type = 8) | OBJ[0xa4] : CREATE DeviceMemory object 0x95
INFO: (IMAGE_VIEW 0x96) [Validation]  [ UNASSIGNED-ObjectTracker-Info ] Object: 0x96 (Type = 14) | OBJ[0xa5] : CREATE ImageView object 0x96
INFO: (RENDER_PASS 0x97) [Validation]  [ UNASSIGNED-ObjectTracker-Info ] Object: 0x97 (Type = 18) | OBJ[0xa6] : CREATE RenderPass object 0x97
INFO: (FRAMEBUFFER 0x98) [Validation]  [ UNASSIGNED-ObjectTracker-Info ] Object: 0x98 (Type = 24) | OBJ[0xa7] : CREATE Framebuffer object 0x98
Toyscene : descriptors, pipeline and descriptors set
INFO: (DESCRIPTOR_SET_LAYOUT 0x99) [Validation]  [ UNASSIGNED-ObjectTracker-Info ] Object: 0x99 (Type = 20) | OBJ[0xa8] : CREATE DescriptorSetLayout object 0x99
INFO: (DESCRIPTOR_SET_LAYOUT 0x9a) [Validation]  [ UNASSIGNED-ObjectTracker-Info ] Object: 0x9a (Type = 20) | OBJ[0xa9] : CREATE DescriptorSetLayout object 0x9a
INFO: (PIPELINE_LAYOUT 0x9b) [Validation]  [ UNASSIGNED-ObjectTracker-Info ] Object: 0x9b (Type = 17) | OBJ[0xaa] : CREATE PipelineLayout object 0x9b
INFO: (PIPELINE_CACHE 0x9c) [Validation]  [ UNASSIGNED-ObjectTracker-Info ] Object: 0x9c (Type = 16) | OBJ[0xab] : CREATE PipelineCache object 0x9c
INFO: (PIPELINE 0x9d) [Validation]  [ UNASSIGNED-ObjectTracker-Info ] Object: 0x9d (Type = 19) | OBJ[0xac] : CREATE Pipeline object 0x9d
INFO: (DESCRIPTOR_SET 0x9e) [Validation]  [ UNASSIGNED-ObjectTracker-Info ] Object: 0x9e (Type = 23) | OBJ[0xad] : CREATE VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT object 0x9e.
INFO: (DESCRIPTOR_SET 0x9f) [Validation]  [ UNASSIGNED-ObjectTracker-Info ] Object: 0x9f (Type = 23) | OBJ[0xae] : CREATE VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT object 0x9f.
INFO: (DESCRIPTOR_SET 0xa0) [Validation]  [ UNASSIGNED-ObjectTracker-Info ] Object: 0xa0 (Type = 23) | OBJ[0xaf] : CREATE VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT object 0xa0.
INFO: (DESCRIPTOR_SET 0xa1) [Validation]  [ UNASSIGNED-ObjectTracker-Info ] Object: 0xa1 (Type = 23) | OBJ[0xb0] : CREATE VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT object 0xa1.
ToyScene : scene prepared OK

Then it would create a simple “cube scene” that uses that texture as source to texture the 6 sides of the cube.

When it renders, and apparently it renders all fine, this is the “validators” output :

'OculusRoomTinVkGiles.exe' (Win32): Loaded 'C:\Windows\System32\oleacc.dll'. Cannot find or open the PDB file.
'OculusRoomTinVkGiles.exe' (Win32): Loaded 'C:\Windows\System32\clbcatq.dll'. Cannot find or open the PDB file.
01/02 20:26:41.282 {INFO}    [Kernel:Default] [HMDState] Detected the active window handle changed to 110a7ell

So ABSOLUTELY NOTHING.

Now this is the way I create that “offline renderpass” :

bool LSRenderer::CreateRenderpass(VkFormat aColorFmt, VkFormat aDepthFmt, VkRenderPass *rp)
{
	VkResult result;
	VkAttachmentDescription attachments[2] = {};	// assume there are 2, could be one
	int a_index = 0;

	if (false == initialized) return false;

	if (aColorFmt != VK_FORMAT_UNDEFINED)
	{
		attachments[a_index].format = aColorFmt; // the surface format
		attachments[a_index].flags = 0;	// this has to be 0
		attachments[a_index].samples = VK_SAMPLE_COUNT_1_BIT;	// we don't do oversampling
		attachments[a_index].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; // initially we decide to CLEAR the contents
		attachments[a_index].storeOp = VK_ATTACHMENT_STORE_OP_STORE; // secondly we decide to KEEP the contents 
		attachments[a_index].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; // we don't care what the stencil is before
		attachments[a_index].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; // we don't care what the stencil is after
		attachments[a_index].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;  // initial layout of the image is UNDEFINED
		attachments[a_index].finalLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; // final layout is FOR SHADER

		a_index++;
	}

	if (aDepthFmt != VK_FORMAT_UNDEFINED)
	{
		attachments[a_index].format = aDepthFmt; // the depth buffer format
		attachments[a_index].flags = 0; // has to be 0
		attachments[a_index].samples = VK_SAMPLE_COUNT_1_BIT; // no oversample here
		attachments[a_index].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;  // clear at start
		attachments[a_index].storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; // we don't need to keep it after
		attachments[a_index].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; // same about this
		attachments[a_index].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; // and that
		attachments[a_index].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; // initial layout is undefined
		attachments[a_index].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; // whatever optimal after it

		//a_index++;
	}

	VkAttachmentReference color_reference{};

	color_reference.attachment = 0;
	color_reference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;

	VkAttachmentReference depth_reference = {};

	depth_reference.attachment = a_index; // could be 0 or 1
	depth_reference.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;

	// we need to set some in/out DEPENDENCIES here !

	VkSubpassDependency dependencies[4];

	dependencies[0].srcSubpass = 0;
	dependencies[0].dstSubpass = VK_SUBPASS_EXTERNAL;
	dependencies[0].srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
	dependencies[0].dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
	dependencies[0].srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
	dependencies[0].dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
	dependencies[0].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
	

	dependencies[1].srcSubpass = 0;
	dependencies[1].dstSubpass = VK_SUBPASS_EXTERNAL;
	dependencies[1].srcStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
	dependencies[1].dstStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
	dependencies[1].srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
	dependencies[1].dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT;
	dependencies[1].dependencyFlags = 0;

	VkSubpassDescription subpass = {};

	subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
	subpass.flags = 0;
	subpass.inputAttachmentCount = 0;
	subpass.pInputAttachments = NULL;
	subpass.colorAttachmentCount = (aColorFmt != VK_FORMAT_UNDEFINED) ? 1 : 0;
	subpass.pColorAttachments = (aColorFmt != VK_FORMAT_UNDEFINED) ? &color_reference : NULL;
	subpass.pResolveAttachments = NULL;
	subpass.pDepthStencilAttachment = (aDepthFmt != VK_FORMAT_UNDEFINED) ? &depth_reference : NULL;
	subpass.preserveAttachmentCount = 0;
	subpass.pPreserveAttachments = NULL;

	VkRenderPassCreateInfo rp_info = {};

	rp_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
	rp_info.pNext = NULL;
	rp_info.flags = 0;
	rp_info.attachmentCount = a_index+1; //  2;
	rp_info.pAttachments = attachments;
	rp_info.subpassCount = 1;
	rp_info.pSubpasses = &subpass;
	rp_info.dependencyCount = 2; // 2
	rp_info.pDependencies = dependencies;

	result = vkCreateRenderPass(DeviceParams.device, &rp_info, NULL, rp);
	assert(result == VK_SUCCESS);

	return true;
}

And this is the way it’s “used” :

	for (i = 0; i < LSREN_MAXSCENES; i++)
	{
		if (OffScreenScenes[i] != nullptr)
		{
			the_rt_used = OffScreenScenes[i]->offscreen_rt;

			rpBegin.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
			rpBegin.pNext = NULL;
			rpBegin.renderPass = RTs[the_rt_used].pass;
			rpBegin.framebuffer = RTs[the_rt_used].fb;
			rpBegin.renderArea = { { 0, 0 }, { (uint32_t) RTs[the_rt_used].tex_width,(uint32_t) RTs[the_rt_used].tex_height} };
			rpBegin.clearValueCount = 2;
			rpBegin.pClearValues = clearValues;

			viewport.x = 0;
			viewport.y = 0;
			viewport.width = RTs[the_rt_used].tex_width;
			viewport.height = RTs[the_rt_used].tex_height;
			viewport.minDepth = 0.0f;
			viewport.maxDepth = 1.0f;

			scissor.extent.width = viewport.width;
			scissor.extent.height = viewport.height;
			scissor.offset.x = 0;
			scissor.offset.y = 0;


			OffScreenScenes[i]->UpdateSceneData(0, index, view);

			vkCmdBeginRenderPass(cmd, &rpBegin, VK_SUBPASS_CONTENTS_INLINE);

			vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, OffScreenScenes[i]->pipeline[view]);


#ifdef _WINDOWS
			// On Oculus Quest it's done outside, in Rift NOT
			vkCmdSetViewport(cmd, 0, 1, &viewport);
			vkCmdSetScissor(cmd, 0, 1, &scissor);
#endif

			vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, OffScreenScenes[i]->pipeline_layout[view], 0, 2,
				&OffScreenScenes[i]->descriptor_set[cb][view][0], 0, NULL);

			of_index = cb % OffScreenScenes[i]->howmanyvbs;

			vkCmdBindVertexBuffers(cmd, 0, 1, &OffScreenScenes[i]->VB.buffer, offsets);

			vkCmdDraw(cmd, OffScreenScenes[i]->VBSizes[of_index], 1, OffScreenScenes[i]->VBOffsets[of_index], 0);

			vkCmdEndRenderPass(cmd);

		}
	}

That’s called by its own, before the scenes that actually use those “offscreen textures” are rendered.

Now the point is if I change these lines :

	rp_info.dependencyCount = 2; // 2
	rp_info.pDependencies = dependencies;

Into this :

	rp_info.dependencyCount = 0; // 2; // 2
	rp_info.pDependencies = NULL; // dependencies;

And I run it all again, validation gets me this ( can’t see any errors or warnings ) :

Toyscene INITSCENE called
ShaderToy_0_Scene::CreateUniformsBuffers : size 64
INFO: (BUFFER 0x80) [Validation]  [ UNASSIGNED-ObjectTracker-Info ] Object: 0x80 (Type = 9) | OBJ[0x8f] : CREATE Buffer object 0x80
INFO: (DEVICE_MEMORY 0x81) [Validation]  [ UNASSIGNED-ObjectTracker-Info ] Object: 0x81 (Type = 8) | OBJ[0x90] : CREATE DeviceMemory object 0x81
INFO: (BUFFER 0x82) [Validation]  [ UNASSIGNED-ObjectTracker-Info ] Object: 0x82 (Type = 9) | OBJ[0x91] : CREATE Buffer object 0x82
INFO: (DEVICE_MEMORY 0x83) [Validation]  [ UNASSIGNED-ObjectTracker-Info ] Object: 0x83 (Type = 8) | OBJ[0x92] : CREATE DeviceMemory object 0x83
INFO: (BUFFER 0x84) [Validation]  [ UNASSIGNED-ObjectTracker-Info ] Object: 0x84 (Type = 9) | OBJ[0x93] : CREATE Buffer object 0x84
INFO: (DEVICE_MEMORY 0x85) [Validation]  [ UNASSIGNED-ObjectTracker-Info ] Object: 0x85 (Type = 8) | OBJ[0x94] : CREATE DeviceMemory object 0x85
INFO: (BUFFER 0x86) [Validation]  [ UNASSIGNED-ObjectTracker-Info ] Object: 0x86 (Type = 9) | OBJ[0x95] : CREATE Buffer object 0x86
INFO: (DEVICE_MEMORY 0x87) [Validation]  [ UNASSIGNED-ObjectTracker-Info ] Object: 0x87 (Type = 8) | OBJ[0x96] : CREATE DeviceMemory object 0x87
Binding 0 , Location 0,  0
Binding 0 , Location 1,  16
Binding 0 , Location 2,  32
Single element size 40, total size 240
INFO: (BUFFER 0x88) [Validation]  [ UNASSIGNED-ObjectTracker-Info ] Object: 0x88 (Type = 9) | OBJ[0x97] : CREATE Buffer object 0x88
INFO: (DEVICE_MEMORY 0x89) [Validation]  [ UNASSIGNED-ObjectTracker-Info ] Object: 0x89 (Type = 8) | OBJ[0x98] : CREATE DeviceMemory object 0x89
Toyscene, texture opened OK
INFO: (SHADER_MODULE 0x8a) [Validation]  [ UNASSIGNED-ObjectTracker-Info ] Object: 0x8a (Type = 15) | OBJ[0x99] : CREATE ShaderModule object 0x8a
INFO: (SHADER_MODULE 0x8b) [Validation]  [ UNASSIGNED-ObjectTracker-Info ] Object: 0x8b (Type = 15) | OBJ[0x9a] : CREATE ShaderModule object 0x8b
Toyscene : shaders all OK
INFO: (SAMPLER 0x8c) [Validation]  [ UNASSIGNED-ObjectTracker-Info ] Object: 0x8c (Type = 21) | OBJ[0x9b] : CREATE Sampler object 0x8c
INFO: (IMAGE 0x8d) [Validation]  [ UNASSIGNED-ObjectTracker-Info ] Object: 0x8d (Type = 10) | OBJ[0x9c] : CREATE Image object 0x8d
INFO: (DEVICE_MEMORY 0x8e) [Validation]  [ UNASSIGNED-ObjectTracker-Info ] Object: 0x8e (Type = 8) | OBJ[0x9d] : CREATE DeviceMemory object 0x8e
There's alredy a sampler set !
INFO: (IMAGE_VIEW 0x8f) [Validation]  [ UNASSIGNED-ObjectTracker-Info ] Object: 0x8f (Type = 14) | OBJ[0x9e] : CREATE ImageView object 0x8f
Toyscene : Offscreen texture creation
INFO: (IMAGE 0x90) [Validation]  [ UNASSIGNED-ObjectTracker-Info ] Object: 0x90 (Type = 10) | OBJ[0x9f] : CREATE Image object 0x90
INFO: (DEVICE_MEMORY 0x91) [Validation]  [ UNASSIGNED-ObjectTracker-Info ] Object: 0x91 (Type = 8) | OBJ[0xa0] : CREATE DeviceMemory object 0x91
INFO: (SAMPLER 0x92) [Validation]  [ UNASSIGNED-ObjectTracker-Info ] Object: 0x92 (Type = 21) | OBJ[0xa1] : CREATE Sampler object 0x92
INFO: (IMAGE_VIEW 0x93) [Validation]  [ UNASSIGNED-ObjectTracker-Info ] Object: 0x93 (Type = 14) | OBJ[0xa2] : CREATE ImageView object 0x93
INFO: (IMAGE 0x94) [Validation]  [ UNASSIGNED-ObjectTracker-Info ] Object: 0x94 (Type = 10) | OBJ[0xa3] : CREATE Image object 0x94
INFO: (DEVICE_MEMORY 0x95) [Validation]  [ UNASSIGNED-ObjectTracker-Info ] Object: 0x95 (Type = 8) | OBJ[0xa4] : CREATE DeviceMemory object 0x95
INFO: (IMAGE_VIEW 0x96) [Validation]  [ UNASSIGNED-ObjectTracker-Info ] Object: 0x96 (Type = 14) | OBJ[0xa5] : CREATE ImageView object 0x96
INFO: (RENDER_PASS 0x97) [Validation]  [ UNASSIGNED-ObjectTracker-Info ] Object: 0x97 (Type = 18) | OBJ[0xa6] : CREATE RenderPass object 0x97
INFO: (FRAMEBUFFER 0x98) [Validation]  [ UNASSIGNED-ObjectTracker-Info ] Object: 0x98 (Type = 24) | OBJ[0xa7] : CREATE Framebuffer object 0x98
Toyscene : descriptors, pipeline and descriptors set
INFO: (DESCRIPTOR_SET_LAYOUT 0x99) [Validation]  [ UNASSIGNED-ObjectTracker-Info ] Object: 0x99 (Type = 20) | OBJ[0xa8] : CREATE DescriptorSetLayout object 0x99
INFO: (DESCRIPTOR_SET_LAYOUT 0x9a) [Validation]  [ UNASSIGNED-ObjectTracker-Info ] Object: 0x9a (Type = 20) | OBJ[0xa9] : CREATE DescriptorSetLayout object 0x9a
INFO: (PIPELINE_LAYOUT 0x9b) [Validation]  [ UNASSIGNED-ObjectTracker-Info ] Object: 0x9b (Type = 17) | OBJ[0xaa] : CREATE PipelineLayout object 0x9b
INFO: (PIPELINE_CACHE 0x9c) [Validation]  [ UNASSIGNED-ObjectTracker-Info ] Object: 0x9c (Type = 16) | OBJ[0xab] : CREATE PipelineCache object 0x9c
INFO: (PIPELINE 0x9d) [Validation]  [ UNASSIGNED-ObjectTracker-Info ] Object: 0x9d (Type = 19) | OBJ[0xac] : CREATE Pipeline object 0x9d
INFO: (DESCRIPTOR_SET 0x9e) [Validation]  [ UNASSIGNED-ObjectTracker-Info ] Object: 0x9e (Type = 23) | OBJ[0xad] : CREATE VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT object 0x9e.
INFO: (DESCRIPTOR_SET 0x9f) [Validation]  [ UNASSIGNED-ObjectTracker-Info ] Object: 0x9f (Type = 23) | OBJ[0xae] : CREATE VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT object 0x9f.
INFO: (DESCRIPTOR_SET 0xa0) [Validation]  [ UNASSIGNED-ObjectTracker-Info ] Object: 0xa0 (Type = 23) | OBJ[0xaf] : CREATE VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT object 0xa0.
INFO: (DESCRIPTOR_SET 0xa1) [Validation]  [ UNASSIGNED-ObjectTracker-Info ] Object: 0xa1 (Type = 23) | OBJ[0xb0] : CREATE VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT object 0xa1.
ToyScene : scene prepared OK

And when it runs, apparently with no differences whatsoever :

'OculusRoomTinVkGiles.exe' (Win32): Loaded 'C:\Windows\System32\UIAutomationCore.dll'. Cannot find or open the PDB file.
'OculusRoomTinVkGiles.exe' (Win32): Loaded 'C:\Windows\System32\oleacc.dll'. Cannot find or open the PDB file.
'OculusRoomTinVkGiles.exe' (Win32): Loaded 'C:\Windows\System32\clbcatq.dll'. Cannot find or open the PDB file.
01/02 20:34:57.773 {INFO}    [Kernel:Default] [HMDState] Detected the active window handle changed to 606f4ll

So again “no meaningful validator output” … and I continue to ask myself “am I doing it right or am I doing it wrong ??”.

Thanks again for your patience.

OK, log only ERRORs and WARNINGs, not the whole thing. You almost never need INFO and DEBUG. If you want to log the api calls for some reason, then VK_LAYER_LUNARG_api_dump is better.

So for your “offscreen render pass” you have only 0EXTERNAL dependencies. So we have to assume all previous work on the resources is done by some other sync means you do not show.

dependencies[0].srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dependencies[0].srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;

Seems correct. This is your storeOp, which happens in this stage for a color attachment.

dependencies[0].dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
dependencies[0].dstAccessMask = VK_ACCESS_SHADER_READ_BIT;

Also seems correct.

So this says in english, that the Image data will be written as color attachment before any sampling in any fragment shader happens in any subsequent render pass instance in the queue.

Now I see you make several similar render pass instances. That means VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT dependency blocks even those. Render pass 0 blocks render pass 1, and so on. It might be better if this Dependency is instead later in the Render Pass that actually samples the images.

dependencies[1].srcStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
dependencies[1].dstStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
dependencies[1].srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
dependencies[1].dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT;

I am assuming you reuse the depth buffer in each of your render pass, otherwisely same as above applies here.

There is bit of a flag spam here. StoreOp for depth attachment happens at VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT. So simply that could be your src from the subpass 0.

Then loadOP happens in VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT. And a clear is VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT. So dst could be simply that.