So, I am trying to understand Vulkan synchronization and subpass dependencies (heh)
I am following this doc here: https://github.com/KhronosGroup/Vulkan-Docs/wiki/Synchronization-Examples#swapchain-image-acquire-and-present
As I understand that's the most up to date?
Specifically trying to understand why the "Combined Graphics/Present Queue" subpass dependencies do what they do.
I found this awesome gist that explained it better than anything else I found: https://gist.github.com/chrisvarns/b4a5dbd1a09545948261d8c650070383
So using that gists style I tried to fill in what the steps on the second subpass mean.
Can anyone validate if the line by line comments of each parameter are correctly describing what it is doing?
VkSubpassDependency dependencies[2] = {
{
// https://gist.github.com/chrisvarns/b4a5dbd1a09545948261d8c650070383
// In subpass zero...
.dstSubpass = 0,
// ... at this pipeline stage ...
.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
// ... wait before performing these operations ...
.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
// ... until all operations of that type stop ...
.srcAccessMask = VK_ACCESS_NONE_KHR,
// ... at that same stages ...
.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
// ... occuring in submission order prior to vkCmdBeginRenderPass ...
.srcSubpass = VK_SUBPASS_EXTERNAL,
// ... have completed execution.
.dependencyFlags = 0,
},
{
// ... In the external scope after the subpass ...
.dstSubpass = VK_SUBPASS_EXTERNAL,
// ... before anything can occur with this pipeline stage ...
.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
// ... wait for all operations to stop ...
.dstAccessMask = VK_ACCESS_NONE_KHR,
// ... of this type ...
.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
// ... at this stage ...
.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
// ... in subpass 0 ...
.srcSubpass = 0,
// ... before it can execute and signal the semaphore rendering complete semaphore
// set to VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT_KHR on vkQueueSubmit2KHR.
},
};
The first dependency says subpass 0 can't start fragment output until previous commands in the stream (before the start of the render pass) have completed their fragment output.
The second dependency says no external (i.e. the next render pass) can start its color attachment output until subpass 0 has completed it's attachment output.
The semaphore on the submit gets signalled when the submitted command buffer is complete (vkQueueSubmit()) or at least past the selected stages (vkQueueSubmit2() with a stageMask). You do need to make sure the frame is rendered before you notify the window system that it is available. Waiting for fragment attachment output is necessary somewhere. This could be enforced inside the submitted commands, or just using the semaphore itself.
Wouldn't the renderingCompleteSemaphore on the presentQueue provide all necessary memory separation and waiting?
For the purposes of the swapchain signalling, yes. But it doesn't provide any guarantee that the graphics workload submits complete in order.
Vulkan commands are specified to start in command queue submission order, but can complete out of order. The dependencies in the main rendering command buffer ensure that the submits retire in-order, which is the desired behavior for frames.
Related
I'm trying to figure out how to use debugPrintfEXT but with no luck.
First I've enabled the extension in my vertex shader
#version 450
#extension GL_EXT_debug_printf : enable
void main()
{
debugPrintfEXT("Test");
// ... some more stuff here ...
}
Then I specify the necessary extensions for the Vulkan instance
VkValidationFeatureEnableEXT enables[] = {VK_VALIDATION_FEATURE_ENABLE_DEBUG_PRINTF_EXT};
VkValidationFeaturesEXT features = {};
features.sType = VK_STRUCTURE_TYPE_VALIDATION_FEATURES_EXT;
features.enabledValidationFeatureCount = 1;
features.pEnabledValidationFeatures = enables;
VkInstanceCreateInfo info = {};
info.pNext = &features;
In the info.ppEnabledExtensionNames field I specified VK_EXT_validation_features and VK_EXT_debug_utils among other things.
When I run my app, I get the following logs
VUID_Undefined(ERROR / SPEC): msgNum: 2044605652 - Validation Error: [ VUID_Undefined ] Object 0: VK_NULL_HANDLE, type = VK_OBJECT_TYPE_DEVICE; | MessageID = 0x79de34d4 | vkCreateDebugUtilsMessengerEXT: value of pCreateInfo->pNext must be NULL. This error is based on the Valid Usage documentation for version 182 of the Vulkan header. It is possible that you are using a struct from a private extension or an extension that was added to a later version of the Vulkan header, in which case the use of pCreateInfo->pNext is undefined and may not work correctly with validation enabled
Objects: 1
[0] 0, type: 3, name: NULL
[Debug][Error][Validation]"Validation Error: [ VUID-VkShaderModuleCreateInfo-pCode-04147 ] Object 0: handle = 0x5651b647e828, type = VK_OBJECT_TYPE_DEVICE; | MessageID = 0x3d492883 | vkCreateShaderModule(): The SPIR-V Extension (SPV_KHR_non_semantic_info) was declared, but none of the requirements were met to use it. The Vulkan spec states: If pCode declares any of the SPIR-V extensions listed in the SPIR-V Environment appendix, one of the corresponding requirements must be satisfied (https://vulkan.lunarg.com/doc/view/1.2.182.0/linux/1.2-extensions/vkspec.html#VUID-VkShaderModuleCreateInfo-pCode-04147)"
What more should I do? And what does
one of the corresponding requirements must be satisfied
mean? Is there something that I'm missing?
Edit:
As suggested by Karl Schultz, it's necessary to add VK_KHR_shader_non_semantic_info to info.ppEnabledExtensionNames.
Also, make sure to set log level to INFO with VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT in VkDebugUtilsMessengerCreateInfoEXT::messageSeverity. By default all the output produced by debugPrintfEXT has INFO level.
You may also see
Printf message was truncated, likely due to a buffer size that was too small for the message
if you spawn too many threads, each printing its own long logs.
You also need to enable the VK_KHR_shader_non_semantic_info device extension in your application code when you create the device.
LunarG has also recently published a white paper about debugPrintfEXT.
I just implemented eventhub with version 5, which has been changed a bit from previous version.
current running code is following:
consumer_client = EventHubConsumerClient.from_connection_string(conn_str=CONNECTION_STR,
consumer_group='fconsumer',
eventhub_name=EVENTHUB_NAME)
consumer_client.receive(on_event=on_event,
partition_id = "0",
track_last_enqueued_event_properties=False,
starting_position="#latest")
By adding an argument for the time duration (or keep_alive ag from prev version), I would make it stop receiving messages and close it after a certain amount of time. Is this possible?
consumer_client.receive(...) will be a blocking call and it won't return on its own. You need to create a thread for consuming events and in the main thread you can get to decide when to close the consumer client. Sample code snippet as below...
thread = threading.Thread(
target=consumer_client.receive,
kwargs={
"on_event": on_event,
"on_partition_initialize": on_partition_initialize,
"on_partition_close": on_partition_close,
"on_error": on_error,
"starting_position": "-1", # "-1" is from the beginning of the partition.
}
)
thread.daemon = True
thread.start()
time.sleep(RECEIVE_DURATION)
consumer_client.close()
thread.join()
Will doing partialupdate() cause code in a data class' onUpdate Handler to run?
I have this setup in the data class:
exports.onUpdate = function(db, obj) {
DB.log.info(obj.ShiftID);
db.Shifts.load(obj.ShiftID)
.then((Shift) => {
DB.log.info(Shift);
if (Shift.User == db.User.me) {
Shift.User = null;
Shift.status = 0;
return Shift.update();
}
})
};
(yes, role 2 for node has permissions to query and update the Shifts data class)
But I am getting zero logs when I make a partialupdate(). Do I need to do a real update query...load the object, modify the data, update()?
Also it seems that this code causes the partialupdate() to not run at all, but when I delete the handler, it starts working again.
Yes, that is currently an unimplemented feature since a partial update can't execute an onUpdate handler since there is no object which can be passed to the update handler.
On the other hand, a partial update can't be executed directly since that will result in a security issue (since your onUpdate handler can contain validation code etc.)
So we currently reject any partial update on a class which has an onUpdate handler because there doesn't exist a way how we can actually validate the partial update against your onUpdate code.
We have planned that you can define an extra onPartial handler where you can take some extra steps before the partialUpdate is executed. But that handler will only get the partial update and not the object itself.
I'm pretty sure that partialupdate() will not cause the onUpdate Handler to run.
When I put the log line in and edit the records using website data manager it does log as expected. Not a big deal, I can just rewrite the query to be a full update.
BUT having any code in there does break partialupdate() which is not good.
Here is the code I'm using that works as long as there is nothing in the onUpdateHandler:
requestShift(shiftID) {
db.ready().then((db) => {
db.Applicants.find()
.where({
"shiftID": { "$in": [shiftID] },
})
.singleResult((applicants) => {
return applicants.partialUpdate()
.add("applicants", db.User.me.id)
.add("photos", this.props.UserData.photo)
.execute()
})
Alert.alert(
'Confirmation',
'Shift has been requested.',
)
this.props.navigation.dispatch(goToFindShifts)
})
}
I'm following the MVVM pattern, and have a model called a DocumentStore. The class has a method as follows:
void DocumentStore::Open_Document(StorageFile^ file) {
create_task(FileIO::ReadTextAsync(file))
.then([this, file](String^ fileContents)
{
// Take the fileContents and add them to internal data structure
});
}
My ViewModel is popping up a FileOpenPicker to get a file that it then feed as the argument into Open_Document:
create_task(picker->PickSingleFileAsync())
.then([this](StorageFile^ file)
{
m_DocStore->Open_Document(file);
// Target location to do something
}
);
I'd like to be able to perform an action after the task inside of Open_Document has completed, i.e. after the fileContents have been processed.
Is there a way for my Model to notify any interested listeners that a task is complete?
Or should my Model's Open_Document method actually be itself asynchronous? However, I need to process the data structure inside the task, and wouldn't that cause my method to be running inside a different thread context?
I'm working in C++/CX but will take any help I can get.
If I understand correctly, the process will be as following.
Open the file -> Read the content -> process the content -> do STH else.
You can push the async operation to the task chain and create a new async operation by using create_async method.
Here is the code for your reference:
create_task(StorageFile::GetFileFromApplicationUriAsync(ref new Windows::Foundation::Uri("ms-appx:///Assets/XMLFile.xml")))
.then([](StorageFile^ file) {
WriteLine("Read the file");
return FileIO::ReadTextAsync(file);
}).then([](task<String^> task) {
String ^ text = task.get();
WriteLine("Content: " + text);
return create_async([text]() {
WriteLine("Process the text: " + text);
});
}).then([](task<void> task) {
task.get();
WriteLine("Do STH else");
});
I'm posting what I ended up going with, but I accepted Jeffrey Chen's answer since it helped me get there.
My Model now has an Event DocOpened. This is fired upon completion of Open_Document. I subscribed my ViewModel to this Event with a handler that is capable of performing tasks whenever that Event is fired.
I have a Schedulable class which will get called once per night. I have run the code anonymously and everything works as it should. The problem I am having is that I cannot get proper test coverage on it! I have written a test class that I believe should work, but for some reason any lines within my for-loops are not being covered.
I assume that it is because no data is being returned from these queries, however there are thousands of records that should be returned. I have run the queries on the production environment without any issues.
Is there a separate process for running queries in a schedulable class?
Here's part of my class:
global class UpdateUnitPrice implements Schedulable{
global void execute(SchedulableContext sc){
// OwnerId -> List of Strings with Row Contents
Map<Id,Map<Id,Map<String,String>>> updateContainer = new Map<Id,Map<Id,Map<String,String>>>{}; // Covered
List<Id> ownerContainer = new List<Id>{}; // Covered
String EmailMessage; // Covered
String EmailLine; // Covered
String EmailAddedLines; // Covered
String CurrentEmailLine; // Covered
String NewEmailLine; // Covered
List<Id> opportunityList = new List<Id>{}; // Covered
for(Opportunity thisOpp :[SELECT Id,Name FROM Opportunity WHERE Order_Proposed__c = null])
{
// Thousands of records should be returned
opportunityList.add(thisOpp.Id); // NOT COVERED!!
}
List<OpportunityLineItem> OppLineItemList = new List<OpportunityLineItem>{}; // Covered
for(OpportunityLineItem thisOppProd : [SELECT Id,OpportunityId,Opportunity.OwnerId,Opportunity.Name,Product_Name__c,UnitPrice,ListPrice
FROM OpportunityLineItem
WHERE OpportunityId IN :opportunityList
AND UnitPrice_lt_ListPrice__c = 'True'
ORDER BY OpportunityId ASC])
{
. . . // NO LINES COVERED WITHIN THIS LOOP
}
. . .
}
}
Here's my test class:
#isTest
private class UpdateUnitPriceTest {
static testMethod void myUnitTest() {
Test.startTest();
// Schedule the test job
String jobId = System.schedule('UpdateUnitPrice','0 0 0 3 9 ? 2022',new UpdateUnitPrice());
// Get the information from the CronTrigger API object
CronTrigger ct = [SELECT Id, CronExpression, TimesTriggered, NextFireTime FROM CronTrigger WHERE id = :jobId];
// Verify the expressions are the same
System.assertEquals(ct.CronExpression,'0 0 0 3 9 ? 2022');
// Verify the job has not run
System.assertEquals(0, ct.TimesTriggered);
// Verify the next time the job will run
System.assertEquals('2022-09-03 00:00:00', String.valueOf(ct.NextFireTime));
Test.stopTest();
}
}
Am I supposed to specifically reference something within these for-loops for them to fire? This Class should be able to just run everything on it's own without inserting records for testing. What am I missing?
Thanks in advance for any help given!
There was a lovely feature added to API 24.0 which requires test classes to include a small (new) line of code in order to view queried data. I have no idea why this was implemented, but it sure did trip me up.
For our test classes to run properly, they now must have the following at the top:
#isTest (SeeAllData = true)
Previously, all that was needed was:
#isTest
You can read more on test classes and this new "feature" here: Apex Test Class Annotations