I have the following setup: One renderpass draws to a texture and the second renderpass draws to a different texture and reads the first one.
To avoid artifacts I added a subpass dependency to the first render pass:
(C# SharpVulkan like code)
SubpassDependency subpassDependency = new SubpassDependency()
{
SourceSubpass = 0,
DestinationSubpass = (~0U),//aka VK_SUBPASS_EXTERNAL
SourceAccessMask = AccessFlags.ColorAttachmentWrite,
SourceStageMask = PipelineStageFlags.ColorAttachmentOutput,
DestinationAccessMask = AccessFlags.ShaderRead,
DestinationStageMask = PipelineStageFlags.FragmentShader,
DependencyFlags = DependencyFlags.ByRegion,
};
This expresses the dependency "The fragment shader of the following renderpass waits until the current render pass finished rendering."
If I try to model the same dependency the other way around "The fragment shader of the current render pass waits until the previous render pass finished rendering" the synchronization fails and I have artifacts in the final image.
SubpassDependency subpassDependency = new SubpassDependency()
{
SourceSubpass = (~0U),//VK_SUBPASS_EXTERNAL,
DestinationSubpass = 0,
SourceAccessMask = AccessFlags.ColorAttachmentWrite,
SourceStageMask = PipelineStageFlags.ColorAttachmentOutput,
DestinationAccessMask = AccessFlags.ShaderRead,
DestinationStageMask = PipelineStageFlags.FragmentShader,
DependencyFlags = DependencyFlags.ByRegion,
};
Quote from the specification:
If srcSubpass is equal to VK_SUBPASS_EXTERNAL, the first synchronization scope includes commands submitted to the queue before the render pass instance began.
I dont understand why the second approach is not working and what are the constraints for the subpass dependency to work. Is there something in the specification I missed ?
If you skip the external dependency in the first renderpass, then a default one is provided. It has dstStageMask of VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT. The automatic transfer to the finalLayout is only guaranteed to happen-before the visibility operation of the external dependency (so, before BOTTOM_OF_PIPE).
In the second renderpass you specify srcStageMask of VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, so I would think there is a race condition between the transfer to finalLayout and first use in the second renderpass.
Related
Here is a Vulkan rendering setup:
Submit CB1 - contains render pass A with X draw calls.
Submit CB2 - contains render pass B with Y draw calls where one of the draw calls samples from image which is render target of render pass A.
During submission of CB2, a semaphore, which is shared with some external GPU API, signaling inserted to make sure CB2 execution is done before the render target of render pass B is used further (By CUDA in this case).This step is set correct and it is clear to me how it works.
All this happens on the same queue and in the above specified order. Render pass A and B share MSAA image,but each has unique color attachment into which MSAA is resolved.
My question is what is the best way to synchronize between CB1 finishing writing to render pass A RT,and one or more draw calls in CB2 sampling from that RT in shader during render pass B execution?
Based on some suggestion I received on Khronos Vulkan Slack group I tried synchronization via subpass dependencies.
Render pass A dependency setup :
VkSubpassDependency dependencies[2] = {};
dependencies[0].srcSubpass = VK_SUBPASS_EXTERNAL;
dependencies[0].dstSubpass = 0;
dependencies[0].srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dependencies[0].dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
dependencies[0].srcAccessMask = VK_ACCESS_MEMORY_READ_BIT;
dependencies[0].dstAccessMask = VK_ACCESS_INPUT_ATTACHMENT_READ_BIT;
dependencies[0].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
VkAttachmentReference colorReferences[2] = {};
colorReferences[0] = { 0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL }; //this one for MSAA attachment
colorReferences[1] = { 1, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL };
Render pass B dependency setup :
VkSubpassDependency dependencies[2] = {};
dependencies[0].srcSubpass = VK_SUBPASS_EXTERNAL;
dependencies[0].dstSubpass = 0;
dependencies[0].srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dependencies[0].dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dependencies[0].srcAccessMask = VK_ACCESS_MEMORY_READ_BIT;
dependencies[0].dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
dependencies[0].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
VkAttachmentReference colorReferences[2] = {};
colorReferences[0] = { 0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL };
colorReferences[1] = { 1, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL };
The above solution seems to be working. But I am not sure I have implicit synchronization guarantee about it. In this discussion one of the answers states
The only images where that isn’t the case is dependencies for render
targets. And those are treated specially by subpasses anyway. Each
subpass says what it is writing and to where, so the system has the
information to build those memory dependencies explicitly.
Also in this article the author writes:
NOTE: Frame buffer operations inside a render pass happen in
API-order, of course. This is a special exception which the spec calls
out.
But in this SO question, the answer is that a sync between command buffers must be done, with events in that case.
So another option I have tried was to insert pipeline memory barrier during CB2 recording for images which are render targets in previously submitted CB (render pass A),before beginning of render pass B recording:
CB2 recording:
BeginCommandBuffer(commandBuffer);
...
if (vulkanTex->isRenderTarget)//for each sampler in this pass
{
VkImageMemoryBarrier imageMemoryBarrier = CreateImageBarrier();
imageMemoryBarrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
imageMemoryBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
imageMemoryBarrier.image = vulkanTex->image;
VkImageSubresourceRange range = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 };
imageMemoryBarrier.subresourceRange = range;
vkCmdPipelineBarrier(
commandBuffer,
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
0,
0, nullptr,
0, nullptr,
1, &imageMemoryBarrier);
}
VkRenderPassBeginInfo renderPassBeginInfo = {};
...
.....
Of course in this scenario, I can set subpass dependency same for all render passes to be like Render pass B dependency setup.This one also works. But it requires from me recording more commands into CBs. So,which way is correct(given subpass dependency option is valid) and most optimal in terms of hardware efficiency?
The above solution seems to be working.
Your dependencies make no sense. The renderpass B dependency in particular is decidedly weird, given your description of the actual dependency: "where one of the draw calls samples from image which is render target of render pass A." That would represent a dependency between the framebuffer writes within A and the texture reads in B. Your dependency in your example creates a dependency between framebuffer writes within A and framebuffer writes within B. Which makes no sense and is unrelated to what you says you're actually doing.
Also, your srcAccessMask makes no sense, as you state that the prior source is reading memory, when you are trying to synchronize with something that is writing memory.
Now, it may be that your semaphore dependency happens to be covering it, or that the semaphore is interfering with Vulkan layers' attempts to detect dependency problems (you are using layers, right?). But the code you've shown simply doesn't make sense.
An external dependency on renderpass B is the right way to go (it's not clear why renderpass A needs an external dependency here), but it needs to actually make sense. If renderpass B is indeed sampling from an image written to by renderpass A, then it would look something like this:
dependencies[0].srcSubpass = VK_SUBPASS_EXTERNAL;
dependencies[0].dstSubpass = 0;
dependencies[0].srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dependencies[0].dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; //Assuming you're reading the image in the fragment shader. Insert other shader stage(s) if otherwise.
dependencies[0].srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; //renderpass A wrote to the image as an attachment.
dependencies[0].dstAccessMask = VK_ACCESS_SHADER_READ_BIT; //renderpass B is reading from the image in a shader.
dependencies[0].dependencyFlags = 0; //By region dependencies make no sense here, since they're not part of the same renderpass.
I'm making a Vulkan (LWJGL) app that will draw directly to framebuffer images. No vertex or fragment shader, just some compute shader to build an image, which I blit directly into a FrameBuffer image. It's working fine.
Now I try to render an UI (imgui) on top of that, but I think I have some synchronization trouble : the UI is blinking sometimes (the blit is maybe not yet finished ?). The render would be perfect for some seconds, but sooner or later, the UI disappears during maybe one frame. I only build the render pass once, I don't record the command buffers more than once for this test, so I think the problem happen when I record the command buffer.
Maybe the problem is that the vkCmdBlitImage is still running when the UI starts to draw ?
I tried to add some barriers, between the blit and the UI render, but the problem is still here.
I think I really miss something, so I'm requesting your help. I put here the code I think relevant, but don't hesitate to ask more code.
The record of the CommandBuffer:
for (int i = 0; i < commandBuffers.size(); i++)
{
RenderCommandBuffer commandBuffer = commandBuffers.get(i);
ImageView imageView = configuration.imageViewManager.getImageViews().get(i);
commandBuffer.startCommand();
copyPixelBufferToFB(commandBuffer, imageView);
commandBuffer.startRenderPass();
imGui.drawFrame(commandBuffer.getVkCommandBuffer());
commandBuffer.endRenderPass();
commandBuffer.endCommand();
}
The copyPixelBufferToFB method:
Extent2D extent = context.swapChainManager.getExtent();
ImageView dstImageView = context.imageViewManager.getImageViews().get(commandBuffer.id);
// Intend to blit from this image, set the layout accordingly
// Prepare transfer from Image to Frambuffer
ImageBarrier barrier = new ImageBarrier(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
VK_PIPELINE_STAGE_TRANSFER_BIT);
barrier.addImageBarrier(srcImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
VK_ACCESS_TRANSFER_READ_BIT);
barrier.addImageBarrier(dstImageView.getImageId(), dstImageView.getImageFormat(), 1, 0,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 0, VK_ACCESS_TRANSFER_WRITE_BIT);
barrier.execute(commandBuffer.getVkCommandBuffer());
long bltSrcImage = srcImage.getId();
long bltDstImage = dstImageView.getImageId();
VkImageBlit.Buffer region = VkImageBlit.calloc(1);
region.srcSubresource().aspectMask(VK_IMAGE_ASPECT_COLOR_BIT);
region.srcSubresource().mipLevel(0);
region.srcSubresource().baseArrayLayer(0);
region.srcSubresource().layerCount(1);
region.srcOffsets(0).x(0);
region.srcOffsets(0).y(0);
region.srcOffsets(0).z(0);
region.srcOffsets(1).x(srcImage.getWidth());
region.srcOffsets(1).y(srcImage.getHeight());
region.srcOffsets(1).z(1);
region.dstSubresource().aspectMask(VK_IMAGE_ASPECT_COLOR_BIT);
region.dstSubresource().mipLevel(0);
region.dstSubresource().baseArrayLayer(0);
region.dstSubresource().layerCount(1);
region.dstOffsets(0).x(0);
region.dstOffsets(0).y(0);
region.dstOffsets(0).z(0);
region.dstOffsets(1).x(extent.getWidth());
region.dstOffsets(1).y(extent.getHeight());
region.dstOffsets(1).z(1);
vkCmdBlitImage(commandBuffer.getVkCommandBuffer(), bltSrcImage,
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, bltDstImage,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, region, VK_FILTER_NEAREST);
// Change layout again before render pass.
ImageBarrier barrierEnd = new ImageBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
barrierEnd.addImageBarrier(srcImage, VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_SHADER_WRITE_BIT);
barrierEnd.addImageBarrier(dstImageView.getImageId(), dstImageView.getImageFormat(), 1,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_WRITE_BIT);
barrierEnd.execute(commandBuffer.getVkCommandBuffer());
How I submit the CommandBuffer, something like that:
bWaitSemaphores.put(waitSemaphore.getId());
bwaitStage.put(VK_PIPELINE_STAGE_TRANSFER_BIT);
pCommandBuffers.put(commandBuffer.getVkCommandBuffer());
submitInfo = VkSubmitInfo.calloc();
submitInfo.sType(VK_STRUCTURE_TYPE_SUBMIT_INFO);
submitInfo.waitSemaphoreCount(bWaitSemaphores.size());
submitInfo.pWaitSemaphores(bWaitSemaphores);
submitInfo.pWaitDstStageMask(bwaitStage);
submitInfo.pCommandBuffers(pCommandBuffers);
[...]
vkQueueSubmit(queue, submitInfo, VK_NULL_HANDLE);
The creation of the RenderPass:
VkAttachmentDescription colorAttachment = VkAttachmentDescription.calloc();
colorAttachment.format(context.swapChainManager.getColorDomain().getColorFormat());
colorAttachment.samples(VK_SAMPLE_COUNT_1_BIT);
colorAttachment.loadOp(VK_ATTACHMENT_LOAD_OP_LOAD);
colorAttachment.storeOp(VK_ATTACHMENT_STORE_OP_STORE);
colorAttachment.stencilLoadOp(VK_ATTACHMENT_LOAD_OP_DONT_CARE);
colorAttachment.stencilStoreOp(VK_ATTACHMENT_STORE_OP_DONT_CARE);
colorAttachment.initialLayout(VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
colorAttachment.finalLayout(VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
VkAttachmentReference.Buffer colorAttachmentRef = VkAttachmentReference.calloc(1);
colorAttachmentRef.attachment(0);
colorAttachmentRef.layout(VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
VkSubpassDescription.Buffer subpass = VkSubpassDescription.calloc(1);
subpass.pipelineBindPoint(VK_PIPELINE_BIND_POINT_GRAPHICS);
subpass.colorAttachmentCount(1);
subpass.pColorAttachments(colorAttachmentRef);
VkSubpassDependency.Buffer dependency = VkSubpassDependency.calloc(1);
dependency.srcSubpass(VK_SUBPASS_EXTERNAL);
dependency.dstSubpass(0);
dependency.srcStageMask(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
dependency.dstStageMask(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
dependency.srcAccessMask(0);
dependency.dstAccessMask(
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT);
int attachmentCount = 1;
VkAttachmentDescription.Buffer attachments = VkAttachmentDescription
.calloc(attachmentCount);
attachments.put(colorAttachment);
attachments.flip();
VkRenderPassCreateInfo renderPassInfo = VkRenderPassCreateInfo.calloc();
renderPassInfo.sType(VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO);
renderPassInfo.pAttachments(attachments);
renderPassInfo.pSubpasses(subpass);
renderPassInfo.pDependencies(dependency);
long[] aRenderPass = new long[1];
if (vkCreateRenderPass(logicalDevice.getVkDevice(), renderPassInfo, null,
aRenderPass) != VK_SUCCESS)
{
throw new AssertionError("Failed to create render pass!");
}
renderPass = aRenderPass[0];
Edit 12/12/2018:
The imGui.drawFrame() in the code above is now irrelevant, I changed the gui from ImGui to Nuklear, and completely rewrote the gui pipeline. Unfortunately, the same problem appears.
However, I'm still using a vkCmdDrawIndexed to draw it.
I have a Image on a stage and I'm drawing over it and erasing it. Using the following method
http://jsfiddle.net/lannymcnie/ZNYPD/
Now i want to take a clone of the user drawings but its not working. I tried
var drawingAreaClone = drawingArea.clone(true);
but its not working .
Is there a way to clone it. kindly Help
The demo you posted doesn't clear the stage, but instead clears the graphics each frame. If you clone the shape, it will have no instructions.
#Catalin's answer is right if you just need a visual -- but another option is to use the Graphics store() method instead of clearing the graphics: http://createjs.com/docs/easeljs/classes/Graphics.html#method_store
Essentially this method just sets an internal pointer to where the graphics draw from. By storing after each draw, only future draw calls are made. This will have the same application as the demo you posted, only you can call unstore() later to reset the Graphics to draw from the beginning. If you clone it this way, it should work.
var erase = document.getElementById("toggle").checked;
wrapper.updateCache(erase?"destination-out":"source-over");
//drawing.graphics.clear();
drawing.graphics.store(); // Don't draw anything before this point
// Later
var newGraphics = drawing.graphics.clone();
newGraphics.unstore(); // Might be redundant
var shape = new Shape(newGraphics);
Note that cloning Graphics doesn't recreate the entire graphics tree, and simply clones the array that stores the instructions. Modifying the individual instructions after the fact would impact any clones of that Graphics object.
Hope that helps.
If the drawn line shape is a child of the drawingAreaClone then the clone should work properly.
However, if for some reason you can't make it work with that, you can take a snapshot of the canvas and save it as an img type varaible like this:
var snapshot = new Image();
snapshot.src = canvas.toDataURL();
Also, if you don't want to snapshot the whole canvas, after you saved the initial image, you can limit the drawing area to a rectangle with these extra instructions:
var ctx = canvas.getContext('2d');
canvas.width = snapshot.width;
canvas.height = snapshot.height;
ctx.drawImage(snapshot, rectangle.x, rectangle.y, rectangle.width, rectangle.height, 0, 0, rectangle.width, rectangle.height);
snapshot.src = canvas.toDataURL();
I'm trying to use NAudio's FadeInOutSampleProvider to fade in a sample and fade it out. The fade in works OK, but instead of fading out gradually I get abrupt silence from where the fade-out should begin.
What's the correct way to fade out with FadeInOutSampleProvider?
Here's how I'm trying to do it:
IWaveProvider waveSource; // initialised by reading a WAV file
// The ISampleProvider will be the underlying source for the following operations
ISampleProvider sampleSource = waveSource.ToSampleProvider();
// Create a provider which defines the samples we want to fade in
// (including the full-volume "middle" of the final output)
ISampleProvider fadeInSource = new OffsetSampleProvider(sampleSource);
fadeInSource.TakeSamples = most_of_file; // calculation omitted for brevity
// Create a provider which defines the samples we want to fade out:
// We will play these samples when fadeInSource is finished
ISampleProvider fadeOutSource = new OffsetSampleProvider(sampleSource);
fadeOutSource.SkipOverSamples = fadeInSource.TakeSamples;
// Wrap the truncated sources in FadeInOutSampleProviders
var fadeIn = new FadeInOutSampleProvider(fadeInSource);
fadeIn.BeginFadeIn(500); // half-second fade
var fadeOut = new FadeInOutSampleProvider(fadeOutSource);
fadeOut.BeginFadeOut(500);
// doc-comments suggest the fade-out will begin "after first Read"
I'm expecting fadeOut to initially read non-zero samples from 500ms before the end of the original source, but fade out to zeros by the end of the source.
However, when I play fadeIn to completion, then play fadeOut, I find that the very first Read call to fadeOut fills the buffer with zeros.
Am I doing something wrong? Or is there a bug in NAudio?
Note: I'm handling the sequential playback using a ConcatenatingSampleProvider which I implemented myself — I can't anything similar in NAudio's API. It's pretty trivial, so I've omitted the source here.
The problem is you're trying to reuse sampleSource twice in your graph. So sampleSource has already been read to the end before anything is read from fadeOutSource. Probably for your usage, it would be better for FadeInOutSampleProvider to be able to "schedule" a fade-out after a known number of samples.
An alternative approach is a FadeOutSampleProvider that caches the fade-out duration, and then when it detects the end of its source has been reached, it returns the cached portion faded out. It does mean latency is introduced.
I'm newbie in using ogre3D and I need help on a certain point!
I'm trying a library mixing ogre3D engine and qtml :
http://advancingusability.wordpress.com/2013/08/14/qmlogre-is-now-a-library/
this library works fine when you want to draw some object and rotate or translate these objects already initialise in a first step.
void initialize(){
// we only want to initialize once
disconnect(this, &ExampleApp::beforeRendering, this, &ExampleApp::initializeOgre);
// start up Ogre
m_ogreEngine = new OgreEngine(this);
m_root = m_ogreEngine->startEngine();
m_ogreEngine->setupResources();
m_ogreEngine->activateOgreContext();
//draw a small cube
new DebugDrawer(m_sceneManager, 0.5f);
DrawCube(100,100,100);
DebugDrawer::getSingleton().build();
m_ogreEngine->doneOgreContext();
emit(ogreInitialized());
}
but If you want to draw or change the scene after this initialisation step it is problematic!
In fact in Ogre3D only (without the qtogre library), you have to use a frameListener
which will connect the rendering thread and allow a repaint of your scene.
But here, we have two ContextOpengl: one for qt and the other one for Ogre.
So If you try to put the common part of code :
createScene();
createFrameListener();
// La Boucle de rendu
m_root->startRendering();
//createScene();
while(true)
{
Ogre::WindowEventUtilities::messagePump();
if(pRenderWindow->isClosed())
std::cout<<"pRenderWindow close"<<std::endl;
if(!m_root->renderOneFrame())
std::cout<<"root renderOneFrame"<<std::endl;
}
the app will freeze! I know that startRendering is a render loop itself, so the loop below never gets executed.
But I don't know where to put those line or how to correct this part!
I've also try to add a background buffer and to swap them :
void OgreEngine::updateOgreContext()
{
glPopAttrib();
glPopClientAttrib();
m_qtContext->functions()->glUseProgram(0);
m_qtContext->doneCurrent();
delete m_qtContext;
m_BackgroundContext= QOpenGLContext::currentContext();
// create a new shared OpenGL context to be used exclusively by Ogre
m_BackgroundContext = new QOpenGLContext();
m_BackgroundContext->setFormat(m_quickWindow->requestedFormat());
m_BackgroundContext->setShareContext(m_qtContext);
m_BackgroundContext->create();
m_BackgroundContext->swapBuffers(m_quickWindow);
//m_ogreContext->makeCurrent(m_quickWindow);
}
but i've also the same error:
OGRE EXCEPTION(7:InternalErrorException): Cannot create GL vertex buffer in GLHardwareVertexBuffer::GLHardwareVertexBuffer at Bureau/bibliotheques/ogre_src_v1-8-1/RenderSystems/GL/src/OgreGLHardwareVertexBuffer.cpp (line 46)
I'm very stuck!
I don't know what to do?
Thanks!