| Index: src/gpu/vk/GrVkGpuCommandBuffer.cpp
|
| diff --git a/src/gpu/vk/GrVkGpuCommandBuffer.cpp b/src/gpu/vk/GrVkGpuCommandBuffer.cpp
|
| index f6104a33083693f28cca8a91c17b47bddaa260a7..1ec82778c42733848a2c889511c04b9eba47f890 100644
|
| --- a/src/gpu/vk/GrVkGpuCommandBuffer.cpp
|
| +++ b/src/gpu/vk/GrVkGpuCommandBuffer.cpp
|
| @@ -7,11 +7,18 @@
|
|
|
| #include "GrVkGpuCommandBuffer.h"
|
|
|
| +#include "GrMesh.h"
|
| +#include "GrPipeline.h"
|
| +#include "GrRenderTargetPriv.h"
|
| +#include "GrTextureAccess.h"
|
| +#include "GrTexturePriv.h"
|
| #include "GrVkCommandBuffer.h"
|
| #include "GrVkGpu.h"
|
| +#include "GrVkPipeline.h"
|
| #include "GrVkRenderPass.h"
|
| #include "GrVkRenderTarget.h"
|
| #include "GrVkResourceProvider.h"
|
| +#include "GrVkTexture.h"
|
|
|
| void get_vk_load_store_ops(GrGpuCommandBuffer::LoadAndStoreOp op,
|
| VkAttachmentLoadOp* loadOp, VkAttachmentStoreOp* storeOp) {
|
| @@ -49,10 +56,11 @@ void get_vk_load_store_ops(GrGpuCommandBuffer::LoadAndStoreOp op,
|
| }
|
|
|
| GrVkGpuCommandBuffer::GrVkGpuCommandBuffer(GrVkGpu* gpu,
|
| - const GrVkRenderTarget& target,
|
| + GrVkRenderTarget* target,
|
| LoadAndStoreOp colorOp, GrColor colorClear,
|
| LoadAndStoreOp stencilOp, GrColor stencilClear)
|
| - : fGpu(gpu) {
|
| + : fGpu(gpu)
|
| + , fRenderTarget(target) {
|
| VkAttachmentLoadOp vkLoadOp;
|
| VkAttachmentStoreOp vkStoreOp;
|
|
|
| @@ -65,21 +73,21 @@ GrVkGpuCommandBuffer::GrVkGpuCommandBuffer(GrVkGpu* gpu,
|
| GrVkRenderPass::LoadStoreOps vkResolveOps(VK_ATTACHMENT_LOAD_OP_LOAD,
|
| VK_ATTACHMENT_STORE_OP_STORE);
|
|
|
| - const GrVkResourceProvider::CompatibleRPHandle& rpHandle = target.compatibleRenderPassHandle();
|
| + const GrVkResourceProvider::CompatibleRPHandle& rpHandle = target->compatibleRenderPassHandle();
|
| if (rpHandle.isValid()) {
|
| fRenderPass = fGpu->resourceProvider().findRenderPass(rpHandle,
|
| vkColorOps,
|
| vkResolveOps,
|
| vkStencilOps);
|
| } else {
|
| - fRenderPass = fGpu->resourceProvider().findRenderPass(target,
|
| + fRenderPass = fGpu->resourceProvider().findRenderPass(*target,
|
| vkColorOps,
|
| vkResolveOps,
|
| vkStencilOps);
|
| }
|
|
|
| fCommandBuffer = GrVkSecondaryCommandBuffer::Create(gpu, gpu->cmdPool(), fRenderPass);
|
| - fCommandBuffer->begin(gpu, target.framebuffer());
|
| + fCommandBuffer->begin(gpu, target->framebuffer());
|
| }
|
|
|
| GrVkGpuCommandBuffer::~GrVkGpuCommandBuffer() {
|
| @@ -87,11 +95,322 @@ GrVkGpuCommandBuffer::~GrVkGpuCommandBuffer() {
|
| fRenderPass->unref(fGpu);
|
| }
|
|
|
| +GrGpu* GrVkGpuCommandBuffer::gpu() { return fGpu; }
|
| +
|
| void GrVkGpuCommandBuffer::end() {
|
| fCommandBuffer->end(fGpu);
|
| }
|
|
|
| -void GrVkGpuCommandBuffer::submit() {
|
| - fGpu->submitSecondaryCommandBuffer(fCommandBuffer);
|
| +void GrVkGpuCommandBuffer::onSubmit(const SkIRect& bounds) {
|
| + // Change layout of our render target so it can be used as the color attachment
|
| + fRenderTarget->setImageLayout(fGpu,
|
| + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
|
| + VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
|
| + VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
|
| + false);
|
| +
|
| + // If we are using a stencil attachment we also need to update its layout
|
| + if (GrStencilAttachment* stencil = fRenderTarget->renderTargetPriv().getStencilAttachment()) {
|
| + GrVkStencilAttachment* vkStencil = (GrVkStencilAttachment*)stencil;
|
| + vkStencil->setImageLayout(fGpu,
|
| + VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
|
| + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT |
|
| + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT,
|
| + VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
|
| + false);
|
| + }
|
| +
|
| + for (int i = 0; i < fSampledImages.count(); ++i) {
|
| + fSampledImages[i]->setImageLayout(fGpu,
|
| + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
|
| + VK_ACCESS_SHADER_READ_BIT,
|
| + VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
|
| + false);
|
| + }
|
| +
|
| + fGpu->submitSecondaryCommandBuffer(fCommandBuffer, fRenderPass, fRenderTarget, bounds);
|
| +}
|
| +
|
| +void GrVkGpuCommandBuffer::onClearStencilClip(GrRenderTarget* target,
|
| + const SkIRect& rect,
|
| + bool insideClip) {
|
| + SkASSERT(target);
|
| +
|
| + GrVkRenderTarget* vkRT = static_cast<GrVkRenderTarget*>(target);
|
| + GrStencilAttachment* sb = target->renderTargetPriv().getStencilAttachment();
|
| + // this should only be called internally when we know we have a
|
| + // stencil buffer.
|
| + SkASSERT(sb);
|
| + int stencilBitCount = sb->bits();
|
| +
|
| + // The contract with the callers does not guarantee that we preserve all bits in the stencil
|
| + // during this clear. Thus we will clear the entire stencil to the desired value.
|
| +
|
| + VkClearDepthStencilValue vkStencilColor;
|
| + memset(&vkStencilColor, 0, sizeof(VkClearDepthStencilValue));
|
| + if (insideClip) {
|
| + vkStencilColor.stencil = (1 << (stencilBitCount - 1));
|
| + } else {
|
| + vkStencilColor.stencil = 0;
|
| + }
|
| +
|
| + VkClearRect clearRect;
|
| + // Flip rect if necessary
|
| + SkIRect vkRect = rect;
|
| +
|
| + if (kBottomLeft_GrSurfaceOrigin == vkRT->origin()) {
|
| + vkRect.fTop = vkRT->height() - rect.fBottom;
|
| + vkRect.fBottom = vkRT->height() - rect.fTop;
|
| + }
|
| +
|
| + clearRect.rect.offset = { vkRect.fLeft, vkRect.fTop };
|
| + clearRect.rect.extent = { (uint32_t)vkRect.width(), (uint32_t)vkRect.height() };
|
| +
|
| + clearRect.baseArrayLayer = 0;
|
| + clearRect.layerCount = 1;
|
| +
|
| + uint32_t stencilIndex;
|
| + SkAssertResult(fRenderPass->stencilAttachmentIndex(&stencilIndex));
|
| +
|
| + VkClearAttachment attachment;
|
| + attachment.aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT;
|
| + attachment.colorAttachment = 0; // this value shouldn't matter
|
| + attachment.clearValue.depthStencil = vkStencilColor;
|
| +
|
| + fCommandBuffer->clearAttachments(fGpu, 1, &attachment, 1, &clearRect);
|
| +}
|
| +
|
| +void GrVkGpuCommandBuffer::onClear(GrRenderTarget* target, const SkIRect& rect, GrColor color) {
|
| + // Currently we should not see clears in vulkan since we are converting them all to draws.
|
| + // We do this since some clears currently can come in the must happen outside a render pass
|
| + // and we assume all commands in this buffer are inside a renderpass.
|
| + SkASSERT(false);
|
| +#if 0
|
| + // parent class should never let us get here with no RT
|
| + SkASSERT(target);
|
| +
|
| + VkClearColorValue vkColor;
|
| + GrColorToRGBAFloat(color, vkColor.float32);
|
| +
|
| + GrVkRenderTarget* vkRT = static_cast<GrVkRenderTarget*>(target);
|
| +
|
| + if (rect.width() != target->width() || rect.height() != target->height()) {
|
| + vkRT->setImageLayout(fGpu,
|
| + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
|
| + VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
|
| + VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
|
| + false);
|
| +
|
| + // If we are using a stencil attachment we also need to change its layout to what the render
|
| + // pass is expecting.
|
| + if (GrStencilAttachment* stencil = vkRT->renderTargetPriv().getStencilAttachment()) {
|
| + GrVkStencilAttachment* vkStencil = (GrVkStencilAttachment*)stencil;
|
| + vkStencil->setImageLayout(fGpu,
|
| + VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
|
| + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT |
|
| + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT,
|
| + VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
|
| + false);
|
| + }
|
| +
|
| + VkClearRect clearRect;
|
| + // Flip rect if necessary
|
| + SkIRect vkRect = rect;
|
| + if (kBottomLeft_GrSurfaceOrigin == vkRT->origin()) {
|
| + vkRect.fTop = vkRT->height() - rect.fBottom;
|
| + vkRect.fBottom = vkRT->height() - rect.fTop;
|
| + }
|
| + clearRect.rect.offset = { vkRect.fLeft, vkRect.fTop };
|
| + clearRect.rect.extent = { (uint32_t)vkRect.width(), (uint32_t)vkRect.height() };
|
| + clearRect.baseArrayLayer = 0;
|
| + clearRect.layerCount = 1;
|
| +
|
| + const GrVkRenderPass* renderPass = vkRT->simpleRenderPass();
|
| + SkASSERT(renderPass);
|
| + fCommandBuffer->beginRenderPass(fGpu, renderPass, *vkRT);
|
| +
|
| + uint32_t colorIndex;
|
| + SkAssertResult(renderPass->colorAttachmentIndex(&colorIndex));
|
| +
|
| + VkClearAttachment attachment;
|
| + attachment.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
| + attachment.colorAttachment = colorIndex;
|
| + attachment.clearValue.color = vkColor;
|
| +
|
| + fCurrentCmdBuffer->clearAttachments(fGpu, 1, &attachment, 1, &clearRect);
|
| + fCurrentCmdBuffer->endRenderPass(fGpu);
|
| + return;
|
| + }
|
| +
|
| + vkRT->setImageLayout(this,
|
| + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
| + VK_ACCESS_TRANSFER_WRITE_BIT,
|
| + VK_PIPELINE_STAGE_TRANSFER_BIT,
|
| + false);
|
| +
|
| + VkImageSubresourceRange subRange;
|
| + memset(&subRange, 0, sizeof(VkImageSubresourceRange));
|
| + subRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
| + subRange.baseMipLevel = 0;
|
| + subRange.levelCount = 1;
|
| + subRange.baseArrayLayer = 0;
|
| + subRange.layerCount = 1;
|
| +
|
| + // In the future we may not actually be doing this type of clear at all. If we are inside a
|
| + // render pass or doing a non full clear then we will use CmdClearColorAttachment. The more
|
| + // common use case will be clearing an attachment at the start of a render pass, in which case
|
| + // we will use the clear load ops.
|
| + fCommandBuffer->clearColorImage(this,
|
| + vkRT,
|
| + &vkColor,
|
| + 1, &subRange);
|
| +#endif
|
| +}
|
| +
|
| +////////////////////////////////////////////////////////////////////////////////
|
| +
|
| +void GrVkGpuCommandBuffer::bindGeometry(const GrPrimitiveProcessor& primProc,
|
| + const GrNonInstancedMesh& mesh) {
|
| + // There is no need to put any memory barriers to make sure host writes have finished here.
|
| + // When a command buffer is submitted to a queue, there is an implicit memory barrier that
|
| + // occurs for all host writes. Additionally, BufferMemoryBarriers are not allowed inside of
|
| + // an active RenderPass.
|
| + GrVkVertexBuffer* vbuf;
|
| + vbuf = (GrVkVertexBuffer*)mesh.vertexBuffer();
|
| + SkASSERT(vbuf);
|
| + SkASSERT(!vbuf->isMapped());
|
| +
|
| + fCommandBuffer->bindVertexBuffer(fGpu, vbuf);
|
| +
|
| + if (mesh.isIndexed()) {
|
| + GrVkIndexBuffer* ibuf = (GrVkIndexBuffer*)mesh.indexBuffer();
|
| + SkASSERT(ibuf);
|
| + SkASSERT(!ibuf->isMapped());
|
| +
|
| + fCommandBuffer->bindIndexBuffer(fGpu, ibuf);
|
| + }
|
| +}
|
| +
|
| +sk_sp<GrVkPipelineState> GrVkGpuCommandBuffer::prepareDrawState(
|
| + const GrPipeline& pipeline,
|
| + const GrPrimitiveProcessor& primProc,
|
| + GrPrimitiveType primitiveType,
|
| + const GrVkRenderPass& renderPass) {
|
| + sk_sp<GrVkPipelineState> pipelineState =
|
| + fGpu->resourceProvider().findOrCreateCompatiblePipelineState(pipeline,
|
| + primProc,
|
| + primitiveType,
|
| + renderPass);
|
| + if (!pipelineState) {
|
| + return pipelineState;
|
| + }
|
| +
|
| + pipelineState->setData(fGpu, primProc, pipeline);
|
| +
|
| + pipelineState->bind(fGpu, fCommandBuffer);
|
| +
|
| + GrVkPipeline::SetDynamicState(fGpu, fCommandBuffer, pipeline);
|
| +
|
| + return pipelineState;
|
| +}
|
| +
|
| +static void append_sampled_images(const GrProcessor& processor,
|
| + const GrVkGpu* gpu,
|
| + SkTArray<GrVkImage*>* sampledImages) {
|
| + if (int numTextures = processor.numTextures()) {
|
| + GrVkImage** images = sampledImages->push_back_n(numTextures);
|
| + int i = 0;
|
| + do {
|
| + const GrTextureAccess& texAccess = processor.textureAccess(i);
|
| + GrVkTexture* vkTexture = static_cast<GrVkTexture*>(processor.texture(i));
|
| + SkASSERT(vkTexture);
|
| + const GrTextureParams& params = texAccess.getParams();
|
| + // Check if we need to regenerate any mip maps
|
| + if (GrTextureParams::kMipMap_FilterMode == params.filterMode()) {
|
| + if (vkTexture->texturePriv().mipMapsAreDirty()) {
|
| + gpu->generateMipmap(vkTexture);
|
| + vkTexture->texturePriv().dirtyMipMaps(false);
|
| + }
|
| + }
|
| +
|
| + images[i] = vkTexture;
|
| + } while (++i < numTextures);
|
| +
|
| + }
|
| +}
|
| +
|
| +void GrVkGpuCommandBuffer::onDraw(const GrPipeline& pipeline,
|
| + const GrPrimitiveProcessor& primProc,
|
| + const GrMesh* meshes,
|
| + int meshCount) {
|
| + if (!meshCount) {
|
| + return;
|
| + }
|
| + GrRenderTarget* rt = pipeline.getRenderTarget();
|
| + GrVkRenderTarget* vkRT = static_cast<GrVkRenderTarget*>(rt);
|
| + const GrVkRenderPass* renderPass = vkRT->simpleRenderPass();
|
| + SkASSERT(renderPass);
|
| +
|
| + GrPrimitiveType primitiveType = meshes[0].primitiveType();
|
| + sk_sp<GrVkPipelineState> pipelineState = this->prepareDrawState(pipeline,
|
| + primProc,
|
| + primitiveType,
|
| + *renderPass);
|
| + if (!pipelineState) {
|
| + return;
|
| + }
|
| +
|
| + append_sampled_images(primProc, fGpu, &fSampledImages);
|
| + for (int i = 0; i < pipeline.numFragmentProcessors(); ++i) {
|
| + append_sampled_images(pipeline.getFragmentProcessor(i), fGpu, &fSampledImages);
|
| + }
|
| + append_sampled_images(pipeline.getXferProcessor(), fGpu, &fSampledImages);
|
| +
|
| + for (int i = 0; i < meshCount; ++i) {
|
| + const GrMesh& mesh = meshes[i];
|
| + GrMesh::Iterator iter;
|
| + const GrNonInstancedMesh* nonIdxMesh = iter.init(mesh);
|
| + do {
|
| + if (nonIdxMesh->primitiveType() != primitiveType) {
|
| + // Technically we don't have to call this here (since there is a safety check in
|
| + // pipelineState:setData but this will allow for quicker freeing of resources if the
|
| + // pipelineState sits in a cache for a while.
|
| + pipelineState->freeTempResources(fGpu);
|
| + SkDEBUGCODE(pipelineState = nullptr);
|
| + primitiveType = nonIdxMesh->primitiveType();
|
| + pipelineState = this->prepareDrawState(pipeline,
|
| + primProc,
|
| + primitiveType,
|
| + *renderPass);
|
| + if (!pipelineState) {
|
| + return;
|
| + }
|
| + }
|
| + SkASSERT(pipelineState);
|
| + this->bindGeometry(primProc, *nonIdxMesh);
|
| +
|
| + if (nonIdxMesh->isIndexed()) {
|
| + fCommandBuffer->drawIndexed(fGpu,
|
| + nonIdxMesh->indexCount(),
|
| + 1,
|
| + nonIdxMesh->startIndex(),
|
| + nonIdxMesh->startVertex(),
|
| + 0);
|
| + } else {
|
| + fCommandBuffer->draw(fGpu,
|
| + nonIdxMesh->vertexCount(),
|
| + 1,
|
| + nonIdxMesh->startVertex(),
|
| + 0);
|
| + }
|
| +
|
| + fGpu->stats()->incNumDraws();
|
| + } while ((nonIdxMesh = iter.next()));
|
| + }
|
| +
|
| + // Technically we don't have to call this here (since there is a safety check in
|
| + // pipelineState:setData but this will allow for quicker freeing of resources if the
|
| + // pipelineState sits in a cache for a while.
|
| + pipelineState->freeTempResources(fGpu);
|
| }
|
|
|
|
|