Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

VulkanRenderManager - big refactoring of the Vulkan code #10033

Merged
merged 28 commits into from
Oct 26, 2017

Conversation

hrydgard
Copy link
Owner

@hrydgard hrydgard commented Oct 25, 2017

This defers the command buffer generation until the end of the frame. This lets us deal with things like transitions and clears in a much better way, and will allow for some pretty cool optimizations in the future. Also, the Vulkan sync framebuffer readback code will later simply flush the queue, wait for completion, perform the copy and start a new "frame" without swapping backbuffers. That's not implemented yet though.

Essentially this reimplements parts of a traditional API driver on top of Vulkan since we can't reorganize games to be more Vulkan-friendly - so we'll have to do it as a post process.

This also contains initial code to do the command buffer generation on another thread while starting the next frame, similarly to what nVidia's D3D11 drivers do in the background. This is not quite working yet, but would be very beneficial on mobile where we have plenty of spare cores and command buffer generation is more expensive than on PC (not sure why that is the case but it is).

Performance impact seems negligible. Possibly because it's beneficial to the instruction cache do a lot of vulkan commands in a row...

This fixes a few games that were broken in Vulkan before like Ridge Racer.

@hrydgard hrydgard changed the title VulkanRenderManager - big refactoring of the Vulkan code WIP: VulkanRenderManager - big refactoring of the Vulkan code Oct 25, 2017
… need to run the swap chain from the thread that created it?
… Add a cap so we can try to unify BlitFramebufferDepth later.
…on of tesselation (should really use separate big desc layouts for them)
@hrydgard hrydgard force-pushed the vulkan-queue-manager branch from e07472f to 7312576 Compare October 26, 2017 09:44
@hrydgard hrydgard changed the title WIP: VulkanRenderManager - big refactoring of the Vulkan code VulkanRenderManager - big refactoring of the Vulkan code Oct 26, 2017
@hrydgard hrydgard merged commit f0a7335 into master Oct 26, 2017
@hrydgard hrydgard deleted the vulkan-queue-manager branch October 26, 2017 11:01
Copy link
Collaborator

@unknownbrackets unknownbrackets left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool. Haven't looked at the follow-ups yet.

-[Unknown]

vp.TopLeftX = (float)x;
vp.TopLeftY = (float)y;
vp.Width = (float)w;
vp.Height = (float)h;
// Since we're about to override it.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment is probably no longer relevant.

@@ -126,7 +126,8 @@ void DrawEngineVulkan::InitDeviceObjects() {
bindings[4].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
bindings[4].stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
bindings[4].binding = DRAW_BINDING_DYNUBO_BONE;
// Hardware tessellation
// Hardware tessellation. TODO: Don't allocate these unless actually drawing splines.
// Will require additional
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you may have forgot to

-[Unknown]

@@ -809,7 +809,7 @@ void FramebufferManagerCommon::SetViewport2D(int x, int y, int w, int h) {
}

void FramebufferManagerCommon::CopyDisplayToOutput() {
DownloadFramebufferOnSwitch(currentRenderVfb_);
// DownloadFramebufferOnSwitch(currentRenderVfb_);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we restore this?

-[Unknown]

step->copy.dst = dst;
step->copy.dstPos = dstPos;

std::unique_lock<std::mutex> lock(mutex_);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, not all pushes to steps_ have locks and I think this mutex_ is no longer used... just noting.

-[Unknown]

res = vkBeginCommandBuffer(cmd, &begin);
assert(res == VK_SUCCESS);

// TODO: Deal with the VK_SUBOPTIMAL_KHR and VK_ERROR_OUT_OF_DATE_KHR
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This TODO has journeyed a little ways from what it once referenced, I think? Also now there is an extra assert here.

-[Unknown]

break;
}
default:
ELOG("Unimpl queue command");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe an assert?

-[Unknown]

}

#if 0
// This part is based on faulty old thinking.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we just delete?

I'm missing what's faulty - although this is definitely suboptimal, and if we're (hopefully) optimizing out clears, it shouldn't be needed as often?

-[Unknown]

void VulkanRenderManager::BindFramebufferAsRenderTarget(VKRFramebuffer *fb, VKRRenderPassAction color, VKRRenderPassAction depth, uint32_t clearColor, float clearDepth, uint8_t clearStencil) {
// Eliminate dupes.
if (steps_.size() && steps_.back()->stepType == VKRStepType::RENDER && steps_.back()->render.framebuffer == fb) {
if (color != VKRRenderPassAction::CLEAR && depth != VKRRenderPassAction::CLEAR) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if we sometimes set clear unnecessarily and create dupes (e.g. that both clear.)

Since our GL code skips dup binds, which improved perf a little... but probably not common, guess we'll see later.

-[Unknown]

renderManager_.CreateBackbuffers();
break;
default:
break;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, why not an assert? I'd rather be explicit, it's not uncommon we'd add an event and forget to update D3D11 or somewhere.

-[Unknown]


renderManager_.BindPipeline(curPipeline_->vkpipeline);
// TODO: blend constants, stencil, viewports should be here, after bindpipeline..
renderManager_.Draw(pipelineLayout_, descSet, 1, &ubo_offset, vulkanVbuf, (int)vbBindOffset, vertexCount);
}

// TODO: We should avoid this function as much as possible, instead use renderpass on-load clearing.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In theory this is no longer true and it's optimized even if we use this func, right? I mean, we should still do this but it's no longer a TODO anyway...

-[Unknown]

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, removing comment.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants