How to translate to Metal the following OpenGL instruction:
glStencilFunc(Func, Ref, Mask);
Let's try to extend Hamid's correct answer with some actual Swift code...
Assuming you already have the basic Metal setup done:
let metalView: MTKView = /* ... */
let commandBuffer: MTLCommandBuffer = /* ... */
let device: MTLDevice = metalView.device!
Let's create a MTLTexture to store the stencil buffer:
let stencilTexture: MTLTexture
// Set up a texture for rendering the *8 bit unsigned* stencil buffer.
let stencilTextureDescriptor = MTLTextureDescriptor()
stencilTextureDescriptor.textureType = .type2D
stencilTextureDescriptor.width = Int(metalView.frame.width)
stencilTextureDescriptor.height = Int(metalView.frame.height)
stencilTextureDescriptor.pixelFormat = .stencil8
stencilTextureDescriptor.storageMode = .private
// Set this option if you use the given texture
// as a stencil render target in any render pass.
stencilTextureDescriptor.usage = [.renderTarget]
stencilTexture = device.makeTexture(descriptor: stencilTextureDescriptor)
Create the MTLRenderPipelineState as usual but be sure to set the stencil attachment too:
let rendePipelineState: MTLRenderPipelineState
let renderPipelineDescriptor = MTLRenderPipelineDescriptor()
/* ...standard render pipeline configuration (e.g., render states, etc)... */
renderPipelineDescriptor.stencilAttachmentPixelFormat = .stencil8
rendePipelineState = try! device.makeRenderPipelineState(descriptor: renderPipelineDescriptor)
Next configure the MTLRenderPassDescriptor and create a MTLRenderCommandEncoder:
let renderEncoder: MTLRenderCommandEncoder
let renderPassDescriptor = MTLRenderPassDescriptor()
renderPassDescriptor.colorAttachments[0].loadAction = .clear
renderPassDescriptor.colorAttachments[0].clearColor = MTLClearColorMake(0, 0, 0, 1)
renderPassDescriptor.colorAttachments[0].storeAction = .store
// Configure these depending on your rendering pass stencil semantics.
renderPassDescriptor.stencilAttachment.texture = stencilTexture
renderPassDescriptor.stencilAttachment.clearStencil = 0
renderPassDescriptor.stencilAttachment.loadAction = .clear
renderPassDescriptor.stencilAttachment.storeAction = .store
renderEncoder = commandBuffer.makeRenderCommandEncoder(descriptor: renderPassDescriptor)!
renderEncoder.setRenderPipelineState(rendePipelineState)
Now create a MTLDepthStencilState with the desired stencil buffer configuration:
let depthAndStencilState: MTLDepthStencilState
let stencilDescriptor = MTLStencilDescriptor()
stencilDescriptor.depthStencilPassOperation = .incrementClamp
// ## glStencilFunc(FUNC, _, _) ##
stencilDescriptor.stencilCompareFunction = .equal
// ## glStencilFunc(_, _, MASK) ##
stencilDescriptor.readMask = 0xFF_FF_FF_FF
let depthAndStencilDescriptor = MTLDepthStencilDescriptor()
depthAndStencilDescriptor.depthCompareFunction = .always
depthAndStencilDescriptor.isDepthWriteEnabled = false
depthAndStencilDescriptor.frontFaceStencil = stencilDescriptor
depthAndStencilDescriptor.backFaceStencil = stencilDescriptor
depthAndStencilState = device.makeDepthStencilState(descriptor: depthAndStencilDescriptor)!
renderEncoder.setDepthStencilState(depthAndStencilState)
// ## glStencilFunc(_, REF, _) ##
renderEncoder.setStencilReferenceValue(1)
Finally, do the rendering as usual:
/* ...encode rendering primitives... */
renderEncoder.endEncoding()
MTLStencilDescriptor an object that defines the front-facing or back-facing stencil operations of a depth and stencil state object.
A stencil test is a comparison between a masked reference value and a
masked value stored in a stencil attachment. (A value is masked by
performing a logical AND operation on it with the readMask value.) The
MTLStencilDescriptor object defines how to update the contents of the
stencil attachment, based on the results of the stencil test and the
depth test.
The stencilCompareFunction property defines the stencil test. The
stencilFailureOperation, depthFailureOperation, and
depthStencilPassOperation properties specify what to do to a stencil
value stored in the stencil attachment for three different test
outcomes: if the stencil test fails, if the stencil test passes and
the depth test fails, or if both stencil and depth tests succeed,
respectively. writeMask determines which stencil bits can be modified
as the result of a stencil operation.
I see where to put the value of Func and Mask with
MTLStencilDescriptor, but where go the value of REF ?
setStencilReferenceValue sets a stencil reference value for both front and back stencil comparison tests.
Related
I am rendering a single mesh test object that contains 8000 cubes, 1 monkey, and 1 plane. I checked normals and winding orders. all seems correct for mesh.
if I render a single instance, the depth buffer works correctly. if I render using instanced when instant number increase depth buffer doesn't work correctly.
//Depth Attachment
//Create Depth Image
depthImage = new Image(
physicalDevice_,
logicalDevice_,
VK_IMAGE_TYPE_2D,
depthFormat,
VK_IMAGE_TILING_OPTIMAL,
swapChainExtent.width,
swapChainExtent.height,
1,
sampleCount_, //do we really need to sample depth????
VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
depthImageView = new ImageView(
logicalDevice_,
VK_IMAGE_VIEW_TYPE_2D,
depthImage->handle,
depthFormat,
1,
VK_IMAGE_ASPECT_DEPTH_BIT);
//Render pass Depth Attachment
VkAttachmentDescription depthAttachment{};
depthAttachment.format = depthFormat;
depthAttachment.samples = VK_SAMPLE_COUNT_1_BIT;
depthAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
depthAttachment.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
depthAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
depthAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
depthAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
depthAttachment.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
//Graphics Pipeline
VkPipelineDepthStencilStateCreateInfo depthStencil{};
depthStencil.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
depthStencil.depthTestEnable = VK_TRUE;
depthStencil.depthWriteEnable = VK_TRUE;
depthStencil.depthCompareOp = VK_COMPARE_OP_LESS;
depthStencil.depthBoundsTestEnable = VK_FALSE;
depthStencil.minDepthBounds = 0.0f; // Optional
depthStencil.maxDepthBounds = 1.0f; // Optional
depthStencil.stencilTestEnable = VK_FALSE;
depthStencil.front = {}; // Optional
depthStencil.back = {}; // Optional
Below the screen is the view from the 100th instance of that mesh.
The higher the instance number, the more the depth buffer deteriorates.
The result is still the same if I use a different model.
What am I missing?
Result:
Depth Buffer:
For those who may struggle with similar issue. I found a solution.
Actually, this issue is not related to instancing directly but it's a bit confusing issue becomes visible as the instance index increases.
the cause is projection matrix z-near value was so small.
...
fieldOfView = 65.0f;
znear = 0.001f; // ! this much small value cause this problem
zfar = 5000.0f;
...
changed z-near to an acceptable value. Problem solved.
...
fieldOfView = 65.0f;
znear = 0.1f;
zfar = 5000.0f;
...
I am trying to mimic the autosave function in GMS v3 so that I can use in version 1 and 2. I would like to first acknowledge that the main bulk of the script originates from Dr Bernhard Schaffer's "How to script... Digital Micrograph Scripting Handbook". I have modified it a bit, so that any new image recorded by the camera can be autosave into the file. However, I met some problems because if I decide to click on live-view image and move the image around, or using live-fft, the live view image or the FFT image will be saved as well. One of the ideas I have is to use the taggroup information such as the "Acquisition:Parameters:Parameter Set Name" because for live view or live-FFT, this would be either in search or focus mode. Another idea is to use the document ID e.g iDocID = idoc.ImageDocumentGETID() to locate the ID of the live image. However, i am clueless then how to use this information to exclude them from autosaving. Can anyone point to me how i can proceed with this script?
Below is the script
Class PeriodicAutoSave : Object
{
Number output
PeriodicAutoSave(Object self) Result("\n Object ID"+self.ScriptObjectGetID()+" created.")
~PeriodicAutoSave(Object self) Result("\n Object ID"+self.ScriptObjectGetID()+" destroyed")
Void Init2(Object self, Number op)
output=op
Void AutoSave_SaveAll(Object self)
{
String path, name, targettype, targettype1, area, mag, mode, search, result1
ImageDocument idoc
Number nr_idoc, count, index_i, index, iDocID, iDocID_search
path = "c:\\path\\"
name = "test"
targettype=="Gatan Format (*.dm4)"
targettype1 = "dm4"
If (output) Result("\n AutoSave...")
nr_idoc = CountImageDocuments()
For (count = 1; count<nr_idoc; count++)
{
idoc = GetImageDocument(count) //imagedocument
index = 1 // user decide the index to start with
index_i= nr_idoc - index
If (idoc.ImageDocumentIsDirty())
{
idoc = getfrontimagedocument()
iDocID = idoc.ImageDocumentGetID()
TagGroup tg = ImageGetTagGroup(idoc.ImageDocumentGetImage(0)) // cannot declare an 'img' for this line as it will prompt an error?
tg.TagGroupGetTagAsString("Microscope Info:Formatted Indicated Mag", mag)
Try{
{
idoc.ImageDocumentSavetoFile( "Gatan Format", path+index_i+"-"+name+"-"+mag+".dm4")
idoc.ImageDocumentSetName(index_i + "-"+name+"-"+mag+".dm4")
idoc.ImageDocumentClean()
}
If (Output) Result("\n\t saving: "+idoc.ImageDocumentGetCurrentFile())
}
Catch{
Result("\n image cannot be saved at the moment:" + GetExceptionString())
Break
}
Result("\ Continue autosave...")
}
}
}
}
Void LaunchAutoSave()
{
Object obj = Alloc(PeriodicAutoSave)
obj.Init2(2)
Number task_id = obj.AddMainThreadPeriodicTask("AutoSave_SaveALL",6)
//Sleep(10)
while(!shiftdown()) 1==2
RemoveMainThreadTask(task_id)
}
LaunchAutoSave()
thank you very much for your pointers! I have tried and it works very well with my script. as the 'TagGroupDoesTagExist' only refers to the taggroup, I modified further to include the tags I want to filter e.g "Search" or "Focus" and it seems to work well. The script that I modified to your existing ones is as below :
If (idoc.ImageDocumentIsDirty())
{
//now find out what is a filter condition and skip if it is true
skip = 0
TagGroup tg = idoc.ImageDocumentGetImage(0).ImageGetTagGroup()
tg.TagGroupGetTagAsString("Microscope Info:Formatted Indicated Mag", mag)
tg.TagGroupGetTagAsString("Acquisition:Parameters:Parameter Set Name", mode)
skip = tg.TagGroupDoesTagExist("Acquisition:Parameters:Parameter Set Name")
if(skip && (mode == "Search" || mode== "Focus")) continue
Your idea of filtering is a good one, but there is something strange with your for loop.
in
nr_idoc = CountImageDocuments()
For (count = 1; count<nr_idoc; count++)
{
idoc = GetImageDocument(count) //imagedocument
you iterate over all currently open imageDocuments (except the first one!?) and get them one by one, but then in
If (idoc.ImageDocumentIsDirty())
{
idoc = getfrontimagedocument()
you actually get the front-most (selected) document instead each time. Why are you doing this?
Why not go with:
number nr_idoc = CountImageDocuments()
for (number count = 0; count<nr_idoc; count++)
{
imagedocument idoc = GetImageDocument(count)
If (idoc.ImageDocumentIsDirty())
{
// now find out what is a filter condition and skip if it is true
number skip = 0
TagGroup tg = idoc.ImageDocumentGetImage(0).ImageGetTagGroup()
skip = tg.TagGroupDoesTagExist("Microscope Info:Formatted Indicated Mag")
if (skip) continue
// do saving
}
}
I have a very simple setup - in fact one of the earlier stages of vkguide.dev. So a single render pass with a single subpass. Those have one color and one depth attachment.
The color AttachmentDescription has .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED and .finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR. In its SubPassDescription, it has .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL.
The depth AttachmentDescription has .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED and .finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL. In its SubPassDescription, it has .layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL.
I'm trying to understand the subpass dependencies, so I don't want to rely on the implicit ones the spec provides but provide my own, minimal ones.
When I provide "zeroed out" subpass dependencies, I get a the following error with sync validation turned on:
Validation Error: [ SYNC-HAZARD-WRITE_AFTER_WRITE ] Object 0: handle = 0x83d4ee000000000b, type = VK_OBJECT_TYPE_RENDER_PASS; | MessageID = 0xfdf9f5e1 | vkCmdBeginRenderPass: Hazard WRITE_AFTER_WRITE vs. layout transition in subpass 0 for attachment 1 aspect depth during load with loadOp VK_ATTACHMENT_LOAD_OP_CLEAR.
So he's complaining about the depth attachment (attachment 1). And I can fix this with the following set of explicit subpass dependencies:
constexpr VkSubpassDependency in_dependency{
.srcSubpass = VK_SUBPASS_EXTERNAL,
.dstSubpass = 0,
.srcStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
.dstStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT,
.srcAccessMask = 0,
.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT
};
constexpr VkSubpassDependency out_dependency = {
.srcSubpass = 0,
.dstSubpass = VK_SUBPASS_EXTERNAL,
.srcStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
.dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
.srcAccessMask = 0,
.dstAccessMask = 0,
.dependencyFlags = 0
};
The second of course is only there to not use the second implicit one and does nothing. The first one is an explicit dependency between things before the renderpass and the first/only subpass. But I don't really understand - a couple of questions:
does a srcAccessMask = 0 really define a real dependency? it's empty after all, or are things different with a VK_SUBPASS_EXTERNAL?
Why do I only need a dependency on the depth- and not on the color attachment?
I made the image below and am aware that color attachment gets loaded and stored in the same pipeline stage, and that the depth attachment does now. However I still don't understand why that eliminates the need for a dependency. That pipeline stage could still overlap between two renderpasses right?
does a srcAccessMask = 0 really define a real dependency? it's empty after all, or are things different with a VK_SUBPASS_EXTERNAL?
Yes it does. It is called an execution dependency (as opposed to memory dependency). It becomes relevant in dependency chaining.
Consider this code:
vkCmdPipelineBarrier(
srcStage = WHATEVER_STAGE, srcAccess = MEMORY_WRITE,
dstStage = COOL_STAGE, dstAccess = 0
);
vkCmdPipelineBarrier(
srcStage = COOL_STAGE, srcAccess = 0,
dstStage = WHATEVER_ELSE_STAGE, dstAccess = MEMORY_READ
);
It is equivalent to a single dependency:
vkCmdPipelineBarrier(
srcStage = WHATEVER_STAGE, srcAccess = MEMORY_WRITE,
dstStage = WHATEVER_ELSE_STAGE, dstAccess = MEMORY_READ
);
Why do I only need a dependency on the depth- and not on the color attachment?
The validation might be implemented imperfectly. Or likely the color attachment is treated differently in your code (the color images are presented, while the depth is not). Which either sneaks the dependency there, or makes it less trivial for the validator to catch.
When using the function vkGetPhysicalDeviceProperties2 I pass a VkPhysicalDeviceProperties2 struct with a VkPhysicalDeviceVulkan11Properties and VkPhysicalDeviceVulkan12Properties in the pNext chain. However, after calling the function, only the vkGetPhysicalDeviceProperties2 contains valid data, the other structures in the chain contain undefined data.
When reviewing the spec, I noticed the comment about other structures Vulkan11 and Vulkan12 structures are supposed to encompass. When replacing them with their corresponding "smaller" structures and adding them to the chain. I do get valid data, which seems even stranger since I don't see what's preventing Vulkan from using the larger structures in the first place.
Note: Validation layers are silent
Info:
Vulkan SDK: 1.2.141.0
Nvidia Driver: 446.14
GPU GeForce GTX 1060 with Max-Q Design
OS: Windows 10.0.18363
Compiler: Microsoft (R) C/C++ Optimizing Compiler Version 19.26.28806 for x64
Relevant Code:
StaticArray<char const *, 1> const RequiredInstanceLayers{
"VK_LAYER_KHRONOS_validation",
};
StaticArray<char const *, 3> const RequiredInstanceExtensions{
VK_KHR_SURFACE_EXTENSION_NAME,
VK_EXT_DEBUG_UTILS_EXTENSION_NAME,
VK_KHR_WIN32_SURFACE_EXTENSION_NAME,
};
VkApplicationInfo ApplicationInfo;
ApplicationInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
ApplicationInfo.pNext = nullptr;
ApplicationInfo.pApplicationName = "Application";
ApplicationInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
ApplicationInfo.pEngineName = "Engine";
ApplicationInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);
ApplicationInfo.apiVersion = VK_API_VERSION_1_2;
VkInstanceCreateInfo InstanceCreateInfo;
InstanceCreateInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
InstanceCreateInfo.pNext = nullptr;
InstanceCreateInfo.flags = 0;
InstanceCreateInfo.pApplicationInfo = &ApplicationInfo;
InstanceCreateInfo.enabledLayerCount = RequiredInstanceLayers.length;
InstanceCreateInfo.ppEnabledLayerNames = RequiredInstanceLayers.data;
InstanceCreateInfo.enabledExtensionCount = RequiredInstanceExtensions.length;
InstanceCreateInfo.ppEnabledExtensionNames = RequiredInstanceExtensions.data;
vkCreateInstance(&InstanceCreateInfo, nullptr, &m_instance);
Uint32 physical_device_count;
vkEnumeratePhysicalDevices(m_instance, &physical_device_count, nullptr);
m_available_physical_devices.Create(m_allocator, physical_device_count);
vkEnumeratePhysicalDevices(m_instance, &physical_device_count, m_available_physical_devices.beg);
for (auto it = m_available_physical_devices.beg; it != m_available_physical_devices.end; ++it)
{
{ // Test 1
VkPhysicalDeviceProperties2 Properties2;
VkPhysicalDeviceVulkan11Properties Vulkan11Properties;
VkPhysicalDeviceVulkan12Properties Vulkan12Properties;
Properties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
Vulkan11Properties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_PROPERTIES;
Vulkan12Properties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_PROPERTIES;
Properties2.pNext = &Vulkan11Properties;
Vulkan11Properties.pNext = &Vulkan12Properties;
Vulkan12Properties.pNext = nullptr;
vkGetPhysicalDeviceProperties2(*it, &Properties2); // only Properties2 is filled out
// Vulkan11Properties and Vulkan12Properties contain undefined data
}
{ // Test 2
VkPhysicalDeviceProperties2 Properties2;
VkPhysicalDeviceDriverProperties DriverProperties;
VkPhysicalDeviceFloatControlsProperties FloatControlsProperties;
VkPhysicalDeviceDescriptorIndexingProperties DescriptorIndexingProperties;
VkPhysicalDeviceDepthStencilResolveProperties DepthStencilResolveProperties;
VkPhysicalDeviceSamplerFilterMinmaxProperties SamplerFilterMinmaxProperties;
VkPhysicalDeviceTimelineSemaphoreProperties TimelineSemaphoreProperties;
VkPhysicalDeviceIDProperties IDProperties;
VkPhysicalDeviceSubgroupProperties SubgroupProperties;
VkPhysicalDevicePointClippingProperties PointClippingProperties;
VkPhysicalDeviceMultiviewProperties MultiviewProperties;
VkPhysicalDeviceProtectedMemoryProperties ProtectedMemoryProperties;
VkPhysicalDeviceMaintenance3Properties Maintenance3Properties;
Properties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
DriverProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES;
FloatControlsProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT_CONTROLS_PROPERTIES;
DescriptorIndexingProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_PROPERTIES;
DepthStencilResolveProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_STENCIL_RESOLVE_PROPERTIES;
SamplerFilterMinmaxProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_FILTER_MINMAX_PROPERTIES;
TimelineSemaphoreProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_PROPERTIES;
IDProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES;
SubgroupProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES;
PointClippingProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_POINT_CLIPPING_PROPERTIES;
MultiviewProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES;
ProtectedMemoryProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_PROPERTIES;
Maintenance3Properties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES;
Properties2.pNext = &DriverProperties;
DriverProperties.pNext = &FloatControlsProperties;
FloatControlsProperties.pNext = &DescriptorIndexingProperties;
DescriptorIndexingProperties.pNext = &DepthStencilResolveProperties;
DepthStencilResolveProperties.pNext = &SamplerFilterMinmaxProperties;
SamplerFilterMinmaxProperties.pNext = &TimelineSemaphoreProperties;
TimelineSemaphoreProperties.pNext = &IDProperties;
IDProperties.pNext = &SubgroupProperties;
SubgroupProperties.pNext = &PointClippingProperties;
PointClippingProperties.pNext = &MultiviewProperties;
MultiviewProperties.pNext = &ProtectedMemoryProperties;
ProtectedMemoryProperties.pNext = &Maintenance3Properties;
Maintenance3Properties.pNext = nullptr;
vkGetPhysicalDeviceProperties2(*it, &Properties2); // every structure is filled out
}
}
Nvidia 446.14 drivers are Vulkan 1.1. VkPhysicalDeviceVulkan11Properties and VkPhysicalDeviceVulkan12Properties both require Vulkan 1.2.
The struct are untouched, because the spec says:
Any component of the implementation (the loader, any enabled layers, and drivers) must skip over, without processing (other than reading the sType and pNext members) any extending structures in the chain not defined by core versions or extensions supported by that component.
On the other hand it is not valid usage:
Each structure present in the pNext chain must be defined at runtime either by a core version which is supported, or by an extension which is enabled.
So Validation layers should ideally be catching this. You should report this at KhronosGroup/Vulkan-ValidationLayers. The problem seems to be the layers check indiscriminately of what version it is, and what extensions are enabled.
I am trying to use the color attachment created in subpass 0 as an input attachment in subpass 1. However there is an issue that i cant get past.
My problem currently is the following, i try to clear attachment 0 at the beginning of the pass using VK_ATTACHMENT_LOAD_OP_CLEAR however gives the error.
Cannot clear attachment 0 with invalid first layout VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL.
Which seems weird to me, attachment 0 does not get layout VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL untill subpass 1 where it is a input attachment, while the clear should have already happened when the layout was still VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL (AFAIK).
I have now tried to just continue running after the validation error, and attachment 0 does get cleared, which makes me even more unsure. I can apparently just ignore the validation error, but something weird might be going on that could cause problems later on so I am not confidant enough to just ignore it.
Here is the minimal code that will give the error:
VkAttachmentDescription attachments[1] {};
attachments[0].format = VK_FORMAT_R16G16B16A16_SFLOAT;
attachments[0].samples = VK_SAMPLE_COUNT_1_BIT;
attachments[0].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
attachments[0].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
attachments[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
attachments[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
attachments[0].initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
attachments[0].finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
VkAttachmentReference pass_0_ColorAttachments[1];
pass_0_ColorAttachments[0].attachment = 0;
pass_0_ColorAttachments[0].layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
VkAttachmentReference pass_1_InputAttachments[1];
pass_1_InputAttachments[0].attachment = 0;
pass_1_InputAttachments[0].layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
VkSubpassDescription subpasses[2] {};
subpasses[0].colorAttachmentCount = 1;
subpasses[0].pColorAttachments = pass_0_ColorAttachments;
subpasses[0].pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
subpasses[1].inputAttachmentCount = 1;
subpasses[1].pInputAttachments = pass_1_InputAttachments;
subpasses[1].pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
VkSubpassDependency subpassDependancies[1] {};
subpassDependancies[0].srcSubpass = 0;
subpassDependancies[0].dstSubpass = 1;
subpassDependancies[0].srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
subpassDependancies[0].dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
subpassDependancies[0].srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
subpassDependancies[0].dstAccessMask = VK_ACCESS_INPUT_ATTACHMENT_READ_BIT;
subpassDependancies[0].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
VkRenderPassCreateInfo renderpassCreateInfo {};
renderpassCreateInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
renderpassCreateInfo.attachmentCount = 1;
renderpassCreateInfo.pAttachments = attachments;
renderpassCreateInfo.subpassCount = 2;
renderpassCreateInfo.pSubpasses = subpasses;
renderpassCreateInfo.dependencyCount = 1;
renderpassCreateInfo.pDependencies = subpassDependancies;
VkRenderPass renderPass;
vkCreateRenderPass(device, &renderpassCreateInfo, nullptr, &renderPass);
The next part is only relevant if it is impossible to specify VK_ATTACHMENT_LOAD_OP_CLEAR for an attachment used as color attachment first and in a later subpass as input attachment (i see no reason why this would be impossible, unless vulkan does the load operation each subpass). So this is kind of a separate problem.
I could, instead of using VK_ATTACHMENT_LOAD_OP_CLEAR, manually clear the attachment using vkCmdClearAttachments and use VK_ATTACHMENT_LOAD_OP_DONT_CARE for the load operation of the attachment.
I have a crash error on calling vkCmdClearAttachments
I started the command buffer recording and the renderpass, and in the first subpass I call:
VkClearAttachment clearAtts[] = {{VK_IMAGE_ASPECT_COLOR_BIT, 1, {0,0,0,0}}};
VkClearRect rect = {{{0,0}, {1,1}}, 0, 1};
vkCmdClearAttachments(vkCommandBuffer, 1, clearAtts, 1, &rect);
{1,1} as the extent to show this is not the problem
You're having the same problem as was discovered here. It's a bug in the validation layer in 1.0.17. It would appear that the current Github head has a fix, but that fix is not in the 1.0.21 release.
But you still need to fix the stuff below ;)
subpassDependancies[0].dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT;
You are not going to read the image as a color attachment. You're going to read it as an input attachment. From the fragment shader. So that would mean VK_ACCESS_INPUT_ATTACHMENT_READ_BIT.
If that fixes the error, then I'd guess the validation layer got confused by your oddball dependency access mask. It therefore couldn't establish a valid dependency chain between subpasses 0 and 1, and thus thought that subpass 1 was first.
Also, your srcStageMask and dstStageMask bits are way over-specified. Every graphics stage is not going to write to the image, and every graphics stage is not going to access it after. You only wrote to the image as a color attachment, and you're only going to read from it in the fragment shader.
So your srcStageMask ought to just be VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, and your dstStageMask ought to be VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT.