Related
I don't quite understand here.:
https://github.com/SaschaWillems/Vulkan/blob/master/examples/computeshader/computeshader.cpp
void draw()
{
VulkanExampleBase::prepareFrame();
submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = &drawCmdBuffers[currentBuffer];
VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE));
VulkanExampleBase::submitFrame();
// Submit compute commands
// Use a fence to ensure that compute command buffer has finished executin before using it again
vkWaitForFences(device, 1, &compute.fence, VK_TRUE, UINT64_MAX);
vkResetFences(device, 1, &compute.fence);
VkSubmitInfo computeSubmitInfo = vks::initializers::submitInfo();
computeSubmitInfo.commandBufferCount = 1;
computeSubmitInfo.pCommandBuffers = &compute.commandBuffer;
VK_CHECK_RESULT(vkQueueSubmit(compute.queue, 1, &computeSubmitInfo, compute.fence));
}
drawCmdBuffers[currentBuffer] runs before compute.commandBuffer, but the consumer drawCmdBuffers[currentBuffer] requires the textureComputeTarget produced by the producer compute.commandBuffer.
I don't understand why drawCmdBuffers[currentBuffer] is called before compute.commandBuffer.
In the following code, only the first frame is rendered, while the right picture does not get the textureComputeTarget, so it is rendered with a blue background.
void draw()
{
VulkanExampleBase::prepareFrame();
submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = &drawCmdBuffers[currentBuffer];
VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE));
VulkanExampleBase::submitFrame();
// Submit compute commands
// Use a fence to ensure that compute command buffer has finished executin before using it again
vkWaitForFences(device, 1, &compute.fence, VK_TRUE, UINT64_MAX);
vkResetFences(device, 1, &compute.fence);
VkSubmitInfo computeSubmitInfo = vks::initializers::submitInfo();
computeSubmitInfo.commandBufferCount = 1;
computeSubmitInfo.pCommandBuffers = &compute.commandBuffer;
VK_CHECK_RESULT(vkQueueSubmit(compute.queue, 1, &computeSubmitInfo, compute.fence));
sleep(1000) // <-------- Wait
}
Executed when calling vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE):
VkImageMemoryBarrier imageMemoryBarrier = {};
imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
// We won't be changing the layout of the image
imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_GENERAL;
imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_GENERAL;
imageMemoryBarrier.image = textureComputeTarget.image;
imageMemoryBarrier.subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 };
imageMemoryBarrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
imageMemoryBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
vkCmdPipelineBarrier(
drawCmdBuffers[i],
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
VK_FLAGS_NONE,
0, nullptr,
0, nullptr,
1, &imageMemoryBarrier);
vkCmdBeginRenderPass(drawCmdBuffers[i], &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
Wait for VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, but this phase has not been executed before, why is the pipeline not stuck? Is it because
there is no pipeline before, so there is no need to wait?
In section 6.6 Pipeline Barriers
vkCmdPipelineBarrier is a synchronization command that inserts a dependency between commands submitted to the same queue, or between commands in the same subpass.
void draw()
{
printf("%p, %p\n", queue, compute.queue);
VulkanExampleBase::prepareFrame();
submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = &drawCmdBuffers[currentBuffer];
VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE));
VulkanExampleBase::submitFrame();
// Submit compute commands
// Use a fence to ensure that compute command buffer has finished executin before using it again
vkWaitForFences(device, 1, &compute.fence, VK_TRUE, UINT64_MAX);
vkResetFences(device, 1, &compute.fence);
VkSubmitInfo computeSubmitInfo = vks::initializers::submitInfo();
computeSubmitInfo.commandBufferCount = 1;
computeSubmitInfo.pCommandBuffers = &compute.commandBuffer;
VK_CHECK_RESULT(vkQueueSubmit(compute.queue, 1, &computeSubmitInfo, compute.fence));
sleep(1000);
}
Print results:
0x6000039c4a20, 0x6000039c4a20
The current queue and compute.queue are the same queue.But it is possible that the above code may generate different queue.
Can VkImageMemoryBarrier be synchronized in multiple queues?
vkCmdPipelineBarrier is a synchronization command that inserts a dependency between commands submitted to the same queue, or
between commands in the same subpass. why use "or", why not use
"and"?
I don't understand why drawCmdBuffers[currentBuffer] is called before compute.commandBuffer.
Dunno, it is an example. Author was probably not awfully woried what happens in the first frame. It would simply be drawn with one frame delay. Swapping the compute before draw should also work with some effort.
Wait for VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, but this phase has not been executed before, why is the pipeline not stuck? Is it because there is no pipeline before, so there is no need to wait?
Because that is not how pipeline and dependencies work. vkCmdPipelineBarrier makes sure any command\operation in queue before the barrier reaches (and finishes) at least the srcStage stage (i.e. COMPUTE) before any command\op recorded after it reach dstStage.
Such dependency is satisfied even if there are no commands recorded before. I.e. by definition of "nothing", there are no commands that have not reached COMPUTE stage yet.
Can VkImageMemoryBarrier be synchronized in multiple queues?
Yes, with the help of a Semaphore.
For VK_SHARING_MODE_EXCLUSIVE and different queue family it is called Queue Family Ownership Transfer (QFOT).
Otherwisely, a Semaphore already performs a memory dependency and a VkImageMemoryBarrier is not needed.
vkCmdPipelineBarrier is a synchronization command that inserts a dependency between commands submitted to the same queue, or between commands in the same subpass. why use "or", why not use "and"?
vkCmdPipelineBarrier is either outside subpass, then it forms a dependency with commands recorded before and after in the queue.
Or vkCmdPipelineBarrier is inside a subpass, in which case it is called "subpass self-dependency" and its scope is limited only to that subpass (among other restrictions).
I am starting with Vulkan and I follow the Niko Kauppi's tutorial on Youtube.
I have an error when creating a device with vkCreateDevice, it returns VK_ERROR_EXTENSION_NOT_PRESENT
Here some part of my code:
The call to vkCreateDevice
_gpu_count = 0;
vkEnumeratePhysicalDevices(instance, &_gpu_count, nullptr);
std::vector<VkPhysicalDevice> gpu_list(_gpu_count);
vkEnumeratePhysicalDevices(instance, &_gpu_count, gpu_list.data());
_gpu = gpu_list[0];
vkGetPhysicalDeviceProperties(_gpu, &_gpu_properties);
VkDeviceCreateInfo device_create_info = _CreateDeviceInfo();
vulkanCheckError(vkCreateDevice(_gpu, &device_create_info, nullptr, &_device));
_gpu_count = 1 and _gpu_properties seems to recognize well my nvidia gpu (which is not up to date)
device_create_info
VkDeviceCreateInfo _createDeviceInfo;
_createDeviceInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
_createDeviceInfo.queueCreateInfoCount = 1;
VkDeviceQueueCreateInfo _queueInfo = _CreateDeviceQueueInfo();
_createDeviceInfo.pQueueCreateInfos = &_queueInfo;
I don't understand the meaning of the error: "A requested extension is not supported" according to Khronos' doc.
Thanks for your help
VK_ERROR_EXTENSION_NOT_PRESENT is returned when one of the extensions in [enabledExtensionCount, ppEnabledExtensionNames] vector you provided is not supported by the driver (as queried by vkEnumerateDeviceExtensionProperties()).
Extensions can also have dependencies, so VK_ERROR_EXTENSION_NOT_PRESENT is also returned when an extension dependency of extension in the list is missing there too.
If you want no device extensions, make sure enabledExtensionCount of VkDeviceCreateInfo is 0 (and not e.g. some uninitialized value).
I assume 2. is the whole body of _CreateDeviceInfo(), which would confirm the "uninitialized value" suspicion.
Usually though you would want a swapchain extension there to be able to render to screen directly.
First of all, make sure your VkDeviceCreateInfo is zero filled, otherwise it may carry garbage to your VkCreateDevice() call.
Add following line just after declaring your VkDeviceCreateInfo:
memset ( &_createDeviceInfo, 0, sizeof(VkDeviceCreateInfo) );
Some extensions are absolutely necessary, as swapchain one.
To retrieve available extensions do this:
// Available extensions and layers names
const char* const* _ppExtensionNames = NULL;
// get extension names
uint32 _extensionCount = 0;
vkEnumerateDeviceExtensionProperties( _gpu, NULL, &_extensionCount, NULL);
std::vector<const char *> extNames;
std::vector<VkExtensionProperties> extProps(_extensionCount);
vkEnumerateDeviceExtensionProperties(_gpu, NULL, &_extensionCount, extProps.data());
for (uint32_t i = 0; i < _extensionCount; i++) {
extNames.push_back(extProps[i].extensionName);
}
_ppExtensionNames = extNames.data();
Once you have all extension names in _ppExtensionNames, pass it to your deviceCreateInfo struct:
VkDeviceCreateInfo device_create_info ...
[...]
device_create_info.enabledExtensionCount = _extensionCount;
device_create_info.ppEnabledExtensionNames = _ppExtensionNames;
[...]
vulkanCheckError(vkCreateDevice(_gpu, &device_create_info, nullptr, &_device));
I hope it helps.
Please double check above code, as I'm writing it by heart.
I was wondering if anyone has found a way to determine the intention of a master communicating with an stm32f40x chip? From the perspective of the firmware on the stm32f40x chip, the ADDRess sent by the master is not available, and the r/w bit (bit 0 of the address) contained therein is also not available. So how can I prevent collisions? Has anyone else dealt with this? If so what techniques did you use? My tentative solution is below for reference. I delayed any writes to the DR data register until the TXE interrupt occurs. I thought at first this would be too late, and a byte of garbage would be clocked out, but it seems to be working.
static inline void LLEVInterrupt(uint16_t irqSrc)
{
uint8_t i;
volatile uint16_t status;
I2CCBStruct* buffers;
I2C_TypeDef* addrBase;
// see which IRQ occurred, process accordingly...
switch (irqSrc)
{
case I2C_BUS_CHAN_1:
addrBase = this.addrBase1;
buffers = &this.buffsBus1;
break;
case I2C_BUS_CHAN_2:
addrBase = this.addrBase2;
buffers = &this.buffsBus2;
break;
case I2C_BUS_CHAN_3:
addrBase = this.addrBase3;
buffers = &this.buffsBus3;
break;
default:
while(1);
}
// ...START condition & address match detected
if (I2C_GetITStatus(addrBase, I2C_IT_ADDR) == SET)
{
// I2C_IT_ADDR: Cleared by software reading SR1 register followed reading SR2, or by hardware
// when PE=0.
// Note: Reading I2C_SR2 after reading I2C_SR1 clears the ADDR flag, even if the ADDR flag was
// set after reading I2C_SR1. Consequently, I2C_SR2 must be read only when ADDR is found
// set in I2C_SR1 or when the STOPF bit is cleared.
status = addrBase->SR1;
status = addrBase->SR2;
// Reset the index and receive count
buffers->txIndex = 0;
buffers->rxCount = 0;
// setup to ACK any Rx'd bytes
I2C_AcknowledgeConfig(addrBase, ENABLE);
return;
}
// Slave receiver mode
if (I2C_GetITStatus(addrBase, I2C_IT_RXNE) == SET)
{
// I2C_IT_RXNE: Cleared by software reading or writing the DR register
// or by hardware when PE=0.
// copy the received byte to the Rx buffer
buffers->rxBuf[buffers->rxCount] = (uint8_t)I2C_ReadRegister(addrBase, I2C_Register_DR);
if (RX_BUFFER_SIZE > buffers->rxCount)
{
buffers->rxCount++;
}
return;
}
// Slave transmitter mode
if (I2C_GetITStatus(addrBase, I2C_IT_TXE) == SET)
{
// I2C_IT_TXE: Cleared by software writing to the DR register or
// by hardware after a start or a stop condition or when PE=0.
// send any remaining bytes
I2C_SendData(addrBase, buffers->txBuf[buffers->txIndex]);
if (buffers->txIndex < buffers->txCount)
{
buffers->txIndex++;
}
return;
}
// ...STOP condition detected
if (I2C_GetITStatus(addrBase, I2C_IT_STOPF) == SET)
{
// STOPF (STOP detection) is cleared by software sequence: a read operation
// to I2C_SR1 register (I2C_GetITStatus()) followed by a write operation to
// I2C_CR1 register (I2C_Cmd() to re-enable the I2C peripheral).
// From the reference manual RM0368:
// Figure 163. Transfer sequence diagram for slave receiver
// if (STOPF == 1) {READ SR1; WRITE CR1}
// clear the IRQ status
status = addrBase->SR1;
// Write to CR1
I2C_Cmd(addrBase, ENABLE);
// read cycle (reset the status?
if (buffers->txCount > 0)
{
buffers->txCount = 0;
buffers->txIndex = 0;
}
// write cycle begun?
if (buffers->rxCount > 0)
{
// pass the I2C data to the enabled protocol handler
for (i = 0; i < buffers->rxCount; i++)
{
#if (COMM_PROTOCOL == COMM_PROTOCOL_DEBUG)
status = ProtProcRxData(buffers->rxBuf[i]);
#elif (COMM_PROTOCOL == COMM_PROTOCOL_PTEK)
status = PTEKProcRxData(buffers->rxBuf[i]);
#else
#error ** Invalid Host Protocol Selected **
#endif
if (status != ST_OK)
{
LogErr(ST_COMM_FAIL, __LINE__);
}
}
buffers->rxCount = 0;
}
return;
}
if (I2C_GetITStatus(addrBase, I2C_IT_AF) == SET)
{
// The NAck received from the host on the last byte of a transmit
// is shown as an acknowledge failure and must be cleared by
// writing 0 to the AF bit in SR1.
// This is not a real error but just how the i2c slave transmission process works.
// The hardware has no way to know how many bytes are to be transmitted, so the
// NAck is assumed to be a failed byte transmission.
// EV3-2: AF=1; AF is cleared by writing ‘0’ in AF bit of SR1 register.
I2C_ClearITPendingBit(addrBase, I2C_IT_AF);
return;
}
if (I2C_GetITStatus(addrBase, I2C_IT_BERR) == SET)
{
// There are extremely infrequent bus errors when testing with I2C Stick.
// Safer to have this check and clear than to risk an
// infinite loop of interrupts
// Set by hardware when the interface detects an SDA rising or falling
// edge while SCL is high, occurring in a non-valid position during a
// byte transfer.
// Cleared by software writing 0, or by hardware when PE=0.
I2C_ClearITPendingBit(addrBase, I2C_IT_BERR);
LogErr(ST_COMM_FAIL, __LINE__);
return;
}
if (I2C_GetITStatus(addrBase, I2C_IT_OVR) == SET)
{
// Check for other errors conditions that must be cleared.
I2C_ClearITPendingBit(addrBase, I2C_IT_OVR);
LogErr(ST_COMM_FAIL, __LINE__);
return;
}
if (I2C_GetITStatus(addrBase, I2C_IT_TIMEOUT) == SET)
{
// Check for other errors conditions that must be cleared.
I2C_ClearITPendingBit(addrBase, I2C_IT_TIMEOUT);
LogErr(ST_COMM_FAIL, __LINE__);
return;
}
// a spurious IRQ occurred; log it
LogErr(ST_INV_STATE, __LINE__);
}
I'm not shure if I understand you. May you should provide more information or an example about what you would like to do.
Maybe this helps:
My experience is, that in many I2C implementations the R/W-Bit is used together with the 7-bit-address, so most of the times, there is no additional function to set or reset the R/W-Bit.
So that means all addresses beyond 128 should be used to read data from slaves and all addresses over 127 should be used to write data to slaves.
There seems to be no way to determine if the transaction initiated by receipt of the address is a read or a write even though the hardware know whether the LSbit is set or clear. The intention of the master will only be known once the RXNE or TXE interrupt/bit occurs.
I'm trying to share a unnamed mach semaphore between two processes.
I can create one and wait on it in the same process.
semaphore_t semaphore = 0;
mach_error_t err = semaphore_create(mach_task_self(), &semaphore, SYNC_POLICY_FIFO, 0);
...
semaphore_wait(semaphore);
But I want to send it to another process (of which I only have the mach_port_t) and then let it semaphore_signal my own process.
I already tried things like:
mach_port_allocate(target, MACH_PORT_RIGHT_RECEIVE, targetSemaphore)
mach_port_insert_right(target, targetSemaphore, semaphore, MACH_MSG_TYPE_COPY_SEND)
Which will yield an error because the port name already exists in the target process or a "unknown failure" if I don't allocate it in the target process.
And even:
mach_msg_send
mach_msg_receive
But I can't even get a port right form one process to anther to send anything.
What am I doing wrong and is it even possible?
I figured it out:
mach_port_extract_right
is correct way, instead of:
mach_port_insert_right
Then doing this, will do the job:
semaphore_t semaphore = 0;
mach_error_t err = semaphore_create(mach_task_self(), &semaphore, SYNC_POLICY_FIFO, 0);
err = mach_port_allocate(target, MACH_PORT_RIGHT_RECEIVE, &receivePort);
mach_msg_type_name_t type;
semaphore_t sendPort = 0;
err = mach_port_extract_right(target, receivePort, MACH_MSG_TYPE_MAKE_SEND, &sendPort, &type);
//Send semaphore using port
mach_msg_send(&msg.header);
I'm trying to use a remote IO connection and route the audio input through the built in filter effect (iOS 5 only) and then back out of the hardware. I can make it route straight from the input to the output but I can't get the filter to work. I'm not sure whether it's the filter Audio Unit or the routing that I've got wrong.
This bit is just my attempt at setting up the filter and changing the routing so that the data is processed by it.
Any help is appreciated.
// ******* BEGIN FILTER ********
NSLog(#"Begin filter");
// Creates Audio Component Description - Output Filter
AudioComponentDescription filterCompDesc;
filterCompDesc .componentType = kAudioUnitType_Effect;
filterCompDesc.componentSubType = kAudioUnitSubType_LowPassFilter;
filterCompDesc.componentManufacturer = kAudioUnitManufacturer_Apple;
filterCompDesc.componentFlags = 1;
filterCompDesc.componentFlagsMask = 1;
// Create Filter Unit
AudioUnit lpFilterUnit;
AudioComponent filterComponent = AudioComponentFindNext(NULL, &filterCompDesc);
setupErr = AudioComponentInstanceNew(filterComponent, &lpFilterUnit);
NSAssert(setupErr == noErr, #"No instance of filter");
AudioUnitElement bus2 = 2;
setupErr = AudioUnitSetProperty(lpFilterUnit, kAudioUnitSubType_LowPassFilter, kAudioUnitScope_Output, bus2, &oneFlag, sizeof(oneFlag));
AudioUnitElement bus3 = 3;
setupErr = AudioUnitSetProperty(lpFilterUnit, kAudioUnitSubType_LowPassFilter, kAudioUnitScope_Input, bus3, &oneFlag, sizeof(oneFlag));
// ******** END FILTER ******** //
AudioUnitConnection hardInToLP;
hardInToLP.sourceAudioUnit = remoteIOunit;
hardInToLP.sourceOutputNumber = 1;
hardInToLP.destInputNumber = 3;
setupErr = AudioUnitSetProperty (
remoteIOunit, // connection destination
kAudioUnitProperty_MakeConnection, // property key
kAudioUnitScope_Input, // destination scope
bus3, // destination element
&hardInToLP, // connection definition
sizeof (hardInToLP)
);
AudioUnitConnection LPToHardOut;
LPToHardOut.sourceAudioUnit = lpFilterUnit;
LPToHardOut.sourceOutputNumber = 1;
LPToHardOut.destInputNumber = 3;
setupErr = AudioUnitSetProperty (
remoteIOunit, // connection destination
kAudioUnitProperty_MakeConnection, // property key
kAudioUnitScope_Input, // destination scope
bus3, // destination element
&hardInToLP, // connection definition
sizeof (hardInToLP)
);
/*
// Sets up the Audio Units Connection - new instance called connection
AudioUnitConnection connection;
// Connect Audio Input's out to Audio Out's in
connection.sourceAudioUnit = remoteIOunit;
connection.sourceOutputNumber = bus1;
connection.destInputNumber = bus0;
setupErr = AudioUnitSetProperty(remoteIOunit, kAudioUnitProperty_MakeConnection, kAudioUnitScope_Input, bus0, &connection, sizeof(connection));
*/
NSAssert(setupErr == noErr, #"No RIO connection");
A couple things going on here:
You're gonna help yourself a lot if you do an assert (or some sort of check-error-and-log-it) after every call that can return an OSStatus. That way you'll figure out how far you're getting. Probably also want to log the actual OSStatus value when it's != noErr, and then look it up (start in "Audio Unit Component Services Reference" in Xcode documentation viewer).
After you create the filter AudioUnit, I don't get what you're doing with the AudioUnitSetProperty() calls. The second parameter should be the name of a property (something that starts with kAudioUnitProperty...). That's almost certainly returning an error right there.
remoteIOunit only has two buses, and they have special meanings. bus 1 is input from the mic, bus 0 is output to hardware. Trying to connect to remote io input scope bus 3 is probably going to be another error
Suggest you roll back to when you had audio pass-through working. That would mean you had just remoteIO, and a connection from output scope / bus 1 to input scope / bus 0.
Then create the filter unit. Change your connections so you connect:
remoteIO output scope bus 1 to filter input scope bus 0
filter output scope bus 0 to remoteIO input scope bus 0
The other thing that's going to be a problem is that all these iOS 5 filters seem to want to use floating-point LPCM formats, which is not the canonical format your other units will default to. You may have to get the stream format from the filter unit (input or output scope are probably the same?) and then set that as the format that remoteIO output scope / bus 1 produces and remoteIO input scope / bus 0 accepts. Another option would be to introduce AUConverter units before and after the filter unit.
The first answer given here just saved me a lot more frustration. No where does the Apple documentation tell you that the file formats for the Effect units require floating point. I couldn't figure out why it kept failing to play my audio properly until I read this post. I followed the advice above and retrieved the stream format from the low pass filter unit, and used that to set up two converter units that I created (ie. set the output format of the pre filter converter, and the input format of the post filter converter. Once I did that and connected all the nodes together it started working as expected.
im trying to use a low pass filter and when trying to do as suggested aka set the format i keep getting an error "the operation could not be completed" what in this code is faulty?
After retrieving the lowpassUnit I also check for errors but there are none.
result = AudioUnitSetProperty(lowpassUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &stereoStreamFormat, sizeof (stereoStreamFormat));
if (noErr != result)
{
NSLog(#"%#", [NSError errorWithDomain:NSOSStatusErrorDomain code:result userInfo:nil]);
return;
}
PS: If anyone knows of proper Audio unit documentation please share as the official documentation is really lacking