I am writing a game for Android using Vulkan. For the game, I need to write the depth buffer information to an offscreen framebuffer. I eventually want to read this depth information with the CPU, but for now I was drawing it on a quad to debug it. I was only getting the clear depth value of 1.0 in the image, so I tried to simplify the problem. First, I decided to use a color and depth attachment in case there was an issue with just the depth attachment. Then I did the following:
(1) set up a render pass which uses color and depth attachments and clears them to green and {1.0, 0} respectively,
(2) use a framebuffer that does not use the swapchain images or normal depth buffer, but images created specifically for this offscreen framebuffer,
(3) transition the layouts so that they can be written to by the render pass,
(4) draw a blue quad which takes up the entire screen to the framebuffer,
(5) end the command buffer and wait for the graphics queue is idle,
(6) transition the layout of the color attachment so that it can be read by a shader,
(7) start a new render pass using the swapchain images in a different command buffer,
(8) draw a quad using for its texture, the results of the previous render pass (color attachment),
(9) end the command buffer and submit to the graphics queue.
What I see is a green rectangle (the clear color from the first render pass) with some blue squares inside of it (blue is the color of the quad drawn in the first render pass). I expected to see the whole screen taken up by a single blue quad.
I feel like I am missing a barrier or fence or semaphore somewhere. But I can't figure out where. I wait on the graphics queue after each command submission (for debugging), I added a semaphore to have each set of commands signal the next set that it was done. So, one would think that there was something wrong in the render pass, but I use this render pass for my normal draw opperations (that are done in the swapchain images and sent to the present queue) without any problem.
Let me know which part of the code you need to see. It is very long.
I enabled the Vulkan validation layers and am getting no complaints from it. I made sure it is working by forcing it to complain.
I did the same thing in OpenGL and it works fine.
My load and store ops are as follows:
colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
colorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
colorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
depthAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
depthAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
depthAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
depthAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
For the layout transitions I am doing the following transition for the color attachment image before the draw:
vkBeginCommandBuffer(...);
VkImageMemoryBarrier barrier = {};
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
barrier.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.image = colorImage;
barrier.subresourceRange.baseMipLevel = 0;
barrier.subresourceRange.levelCount = 1;
barrier.subresourceRange.baseArrayLayer = 0;
barrier.subresourceRange.layerCount = 1;
barrier.srcAccessMask = 0;
barrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
sourceStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
destinationStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
vkCmdPipelineBarrier(
cmdBuffer,
sourceStage, destinationStage,
0,
0, nullptr,
0, nullptr,
1, &barrier
);
vkEndCommandBuffer(...);
vkQueueSubmit(...);
vkQueueWaitIdle(graphicsQueue);
In the render pass, I transition the layout to VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL so that I can read it from the shader.
colorAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
colorAttachment.finalLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
VkAttachmentReference colorAttachmentRef = {};
colorAttachmentRef.attachment = 0;
colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
The subpass and its dependencies:
VkSubpassDescription subpass = {};
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
subpass.colorAttachmentCount = 1;
subpass.pColorAttachments = &colorAttachmentRef;
subpass.pDepthStencilAttachment = &depthAttachmentRef;
VkSubpassDependency dependency = {};
dependency.srcSubpass = VK_SUBPASS_EXTERNAL;
dependency.dstSubpass = 0;
dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dependency.srcAccessMask = 0;
dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dependency.dstAccessMask =
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
My final goal is to have a render pass with no color attachment, only a depth attachment. The color attachment is there for debug purposes only.
My thought on this problem is that it is a driver bug. The code works fine on a couple of different Linux PCs and on a Pixel 4XL android device. I put a test in to see if I get the correct result for a known model. If the answer comes back incorrect, I fall back to OpenGL.
Related
I'm developing an app with blazor client-side and I need to render a 3D scene.
I have an issue and I guess it is material-related.
I have a composition of parallelepipeds where one of them is fully opaque and the others are transparent.
Depending on the camera angle, the transparent ones completely disappear:
Example where everything is visible:
Example with 2 missing:
Example with all missing:
Code for transparent parallelepipeds
var geometry = new THREE.CubeGeometry(item.xDimension * _scene.normalizer, item.yDimension * _scene.normalizer, item.zDimension * _scene.normalizer);
var material = new THREE.MeshBasicMaterial();
var box = new THREE.Mesh(geometry, material);
box.material.color = new THREE.Color("gray");
box.material.opacity = 0.8;
box.material.transparent = true;
Code for the camera:
var camera = new THREE.PerspectiveCamera(60, width / height, 0.1, 100);
camera.position.set(1.3, 1.3, 1.3);
camera.lookAt(0, 0, 0);
I'm using OrbitControls and every object size is between 0 an 1 (_scene.normalizer is for that purpose)
Do you know why this is happening?
Edit:
I found it being a material depth function issue. Do you know which should I use?
Thanks,
Transparency is tricky with WebGL because a transparent object writes to the depthmap, and then the renderer assumes that subsequent objects behind it are occluded so it skips drawing them. You could avoid this by playing with the material's .depthTest and .depthWrite attributes (see the docs):
box.material.color = new THREE.Color("gray");
box.material.opacity = 0.8;
box.material.transparent = true;
box.material.depthWrite = false;
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();
Hi i need to create a texture that is made up of other textures overlayed. I've tried using pixmap however it is noticably slow. The idea is to create a "snapshot" of a dialog so that it can be animated as it shows up and when it is dismissed. Please help
This is the code that I am using:
texture_dialog.getTextureData().prepare();
Pixmap pm1 = texture_dialog.getTextureData().consumePixmap();
btn_ok.getTexture().getTextureData().prepare();
Pixmap pm = btn_ok.getTexture().getTextureData().consumePixmap();
pm1.drawPixmap(pm, pm1.getWidth()/2 - pm.getWidth()/2, pm1.getHeight() - pm.getHeight() - 52);
textureSnapShot = new Texture(pm1, true);
pm1.dispose();
pm.dispose();
textureSnapShot.setFilter(TextureFilter.MipMapLinearLinear, TextureFilter.MipMapLinearLinear);
spriteSnapShot = new Sprite(textureSnapShot);
I've tried using a FrameBuffer as follows:
SpriteBatch sb = new SpriteBatch();
sb.setProjectionMatrix(camera.combined);
FrameBuffer fbo = new FrameBuffer(Format.RGBA8888, texture_dialog.getWidth(), texture_dialog.getHeight(), false);
fbo.begin();
sb.begin();
sb.draw(texture_dialog, 0, 0);
sb.draw(btn_ok.getTexture(), texture_dialog.getWidth()/2 - btn_ok.getWidth()/2, 52);
sb.end();
fbo.end();
sb.dispose();
textureSnapShot = fbo.getColorBufferTexture();
//textureSnapShot.setFilter(TextureFilter.MipMapLinearLinear, TextureFilter.MipMapLinearLinear);
spriteSnapShot = new Sprite(textureSnapShot);
The results are as follows:
http://medialinestudio.co.za/screens.png
Left: Pixmap Right: FrameBuffer
Pixmap has the correct result but too slow. FrameBuffer is faster but incorrect result
FBO is definitely what you should use for your need.
read this post : libgdx SpriteBatch render to texture
what you missing is :
create a camera with correct width/height and position to fit your drawing inside the FBO viewport (0,0,Width,Height)
flip the output texture (m_fboRegion.flip(false, true))