1/* 2 * Copyright 2016 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8#include "src/gpu/vk/GrVkOpsRenderPass.h" 9 10#include "include/core/SkDrawable.h" 11#include "include/core/SkRect.h" 12#include "include/gpu/GrBackendDrawableInfo.h" 13#include "include/gpu/GrDirectContext.h" 14#include "src/core/SkTraceEvent.h" 15#include "src/gpu/GrBackendUtils.h" 16#include "src/gpu/GrDirectContextPriv.h" 17#include "src/gpu/GrOpFlushState.h" 18#include "src/gpu/GrPipeline.h" 19#include "src/gpu/GrRenderTarget.h" 20#include "src/gpu/effects/GrTextureEffect.h" 21#include "src/gpu/vk/GrVkBuffer.h" 22#include "src/gpu/vk/GrVkCommandBuffer.h" 23#include "src/gpu/vk/GrVkCommandPool.h" 24#include "src/gpu/vk/GrVkFramebuffer.h" 25#include "src/gpu/vk/GrVkGpu.h" 26#include "src/gpu/vk/GrVkImage.h" 27#include "src/gpu/vk/GrVkImageView.h" 28#include "src/gpu/vk/GrVkPipeline.h" 29#include "src/gpu/vk/GrVkRenderPass.h" 30#include "src/gpu/vk/GrVkRenderTarget.h" 31#include "src/gpu/vk/GrVkResourceProvider.h" 32#include "src/gpu/vk/GrVkSemaphore.h" 33#include "src/gpu/vk/GrVkTexture.h" 34 35///////////////////////////////////////////////////////////////////////////// 36 37void get_vk_load_store_ops(GrLoadOp loadOpIn, GrStoreOp storeOpIn, 38 VkAttachmentLoadOp* loadOp, VkAttachmentStoreOp* storeOp) { 39 switch (loadOpIn) { 40 case GrLoadOp::kLoad: 41 *loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; 42 break; 43 case GrLoadOp::kClear: 44 *loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; 45 break; 46 case GrLoadOp::kDiscard: 47 *loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; 48 break; 49 default: 50 SK_ABORT("Invalid LoadOp"); 51 *loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; 52 } 53 54 switch (storeOpIn) { 55 case GrStoreOp::kStore: 56 *storeOp = VK_ATTACHMENT_STORE_OP_STORE; 57 break; 58 case GrStoreOp::kDiscard: 59 *storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; 60 break; 61 default: 62 SK_ABORT("Invalid StoreOp"); 63 *storeOp = VK_ATTACHMENT_STORE_OP_STORE; 64 } 65} 66 67GrVkOpsRenderPass::GrVkOpsRenderPass(GrVkGpu* gpu) : fGpu(gpu) {} 68 69void GrVkOpsRenderPass::setAttachmentLayouts(LoadFromResolve loadFromResolve) { 70 bool withStencil = fCurrentRenderPass->hasStencilAttachment(); 71 bool withResolve = fCurrentRenderPass->hasResolveAttachment(); 72 73 if (fSelfDependencyFlags == SelfDependencyFlags::kForInputAttachment) { 74 // We need to use the GENERAL layout in this case since we'll be using texture barriers 75 // with an input attachment. 76 VkAccessFlags dstAccess = VK_ACCESS_INPUT_ATTACHMENT_READ_BIT | 77 VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | 78 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; 79 VkPipelineStageFlags dstStages = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | 80 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; 81 fFramebuffer->colorAttachment()->setImageLayout( 82 fGpu, VK_IMAGE_LAYOUT_GENERAL, dstAccess, dstStages, false); 83 } else { 84 // Change layout of our render target so it can be used as the color attachment. 85 // TODO: If we know that we will never be blending or loading the attachment we could drop 86 // the VK_ACCESS_COLOR_ATTACHMENT_READ_BIT. 87 fFramebuffer->colorAttachment()->setImageLayout( 88 fGpu, 89 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, 90 VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, 91 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 92 false); 93 } 94 95 if (withResolve) { 96 GrVkImage* resolveAttachment = fFramebuffer->resolveAttachment(); 97 SkASSERT(resolveAttachment); 98 if (loadFromResolve == LoadFromResolve::kLoad) { 99 resolveAttachment->setImageLayout(fGpu, 100 VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, 101 VK_ACCESS_INPUT_ATTACHMENT_READ_BIT, 102 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 103 false); 104 } else { 105 resolveAttachment->setImageLayout( 106 fGpu, 107 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, 108 VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, 109 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 110 false); 111 } 112 } 113 114 // If we are using a stencil attachment we also need to update its layout 115 if (withStencil) { 116 auto* vkStencil = fFramebuffer->stencilAttachment(); 117 SkASSERT(vkStencil); 118 119 // We need the write and read access bits since we may load and store the stencil. 120 // The initial load happens in the VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT so we 121 // wait there. 122 vkStencil->setImageLayout(fGpu, 123 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, 124 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | 125 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT, 126 VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT, 127 false); 128 } 129} 130 131// The RenderArea bounds we pass into BeginRenderPass must have a start x value that is a multiple 132// of the granularity. The width must also be a multiple of the granularity or eaqual to the width 133// the the entire attachment. Similar requirements for the y and height components. 134void adjust_bounds_to_granularity(SkIRect* dstBounds, 135 const SkIRect& srcBounds, 136 const VkExtent2D& granularity, 137 int maxWidth, 138 int maxHeight) { 139 // Adjust Width 140 if ((0 != granularity.width && 1 != granularity.width)) { 141 // Start with the right side of rect so we know if we end up going pass the maxWidth. 142 int rightAdj = srcBounds.fRight % granularity.width; 143 if (rightAdj != 0) { 144 rightAdj = granularity.width - rightAdj; 145 } 146 dstBounds->fRight = srcBounds.fRight + rightAdj; 147 if (dstBounds->fRight > maxWidth) { 148 dstBounds->fRight = maxWidth; 149 dstBounds->fLeft = 0; 150 } else { 151 dstBounds->fLeft = srcBounds.fLeft - srcBounds.fLeft % granularity.width; 152 } 153 } else { 154 dstBounds->fLeft = srcBounds.fLeft; 155 dstBounds->fRight = srcBounds.fRight; 156 } 157 158 // Adjust height 159 if ((0 != granularity.height && 1 != granularity.height)) { 160 // Start with the bottom side of rect so we know if we end up going pass the maxHeight. 161 int bottomAdj = srcBounds.fBottom % granularity.height; 162 if (bottomAdj != 0) { 163 bottomAdj = granularity.height - bottomAdj; 164 } 165 dstBounds->fBottom = srcBounds.fBottom + bottomAdj; 166 if (dstBounds->fBottom > maxHeight) { 167 dstBounds->fBottom = maxHeight; 168 dstBounds->fTop = 0; 169 } else { 170 dstBounds->fTop = srcBounds.fTop - srcBounds.fTop % granularity.height; 171 } 172 } else { 173 dstBounds->fTop = srcBounds.fTop; 174 dstBounds->fBottom = srcBounds.fBottom; 175 } 176} 177 178bool GrVkOpsRenderPass::beginRenderPass(const VkClearValue& clearColor, 179 LoadFromResolve loadFromResolve) { 180 this->setAttachmentLayouts(loadFromResolve); 181 182 bool firstSubpassUsesSecondaryCB = 183 loadFromResolve != LoadFromResolve::kLoad && SkToBool(fCurrentSecondaryCommandBuffer); 184 185 bool useFullBounds = fCurrentRenderPass->hasResolveAttachment() && 186 fGpu->vkCaps().mustLoadFullImageWithDiscardableMSAA(); 187 188 auto dimensions = fFramebuffer->colorAttachment()->dimensions(); 189 190 auto nativeBounds = GrNativeRect::MakeIRectRelativeTo( 191 fOrigin, 192 dimensions.height(), useFullBounds ? SkIRect::MakeSize(dimensions) : fBounds); 193 194 // The bounds we use for the render pass should be of the granularity supported 195 // by the device. 196 const VkExtent2D& granularity = fCurrentRenderPass->granularity(); 197 SkIRect adjustedBounds; 198 if ((0 != granularity.width && 1 != granularity.width) || 199 (0 != granularity.height && 1 != granularity.height)) { 200 adjust_bounds_to_granularity(&adjustedBounds, 201 nativeBounds, 202 granularity, 203 dimensions.width(), 204 dimensions.height()); 205 } else { 206 adjustedBounds = nativeBounds; 207 } 208 209 if (!fGpu->beginRenderPass(fCurrentRenderPass, fFramebuffer, &clearColor, fRenderTarget, 210 adjustedBounds, firstSubpassUsesSecondaryCB)) { 211 if (fCurrentSecondaryCommandBuffer) { 212 fCurrentSecondaryCommandBuffer->end(fGpu); 213 } 214 fCurrentRenderPass = nullptr; 215 return false; 216 } 217 218 if (loadFromResolve == LoadFromResolve::kLoad) { 219 this->loadResolveIntoMSAA(adjustedBounds); 220 } 221 222 return true; 223} 224 225bool GrVkOpsRenderPass::init(const GrOpsRenderPass::LoadAndStoreInfo& colorInfo, 226 const GrOpsRenderPass::LoadAndStoreInfo& resolveInfo, 227 const GrOpsRenderPass::StencilLoadAndStoreInfo& stencilInfo) { 228 VkAttachmentLoadOp loadOp; 229 VkAttachmentStoreOp storeOp; 230 get_vk_load_store_ops(colorInfo.fLoadOp, colorInfo.fStoreOp, &loadOp, &storeOp); 231 GrVkRenderPass::LoadStoreOps vkColorOps(loadOp, storeOp); 232 233 get_vk_load_store_ops(resolveInfo.fLoadOp, resolveInfo.fStoreOp, &loadOp, &storeOp); 234 GrVkRenderPass::LoadStoreOps vkResolveOps(loadOp, storeOp); 235 236 get_vk_load_store_ops(stencilInfo.fLoadOp, stencilInfo.fStoreOp, &loadOp, &storeOp); 237 GrVkRenderPass::LoadStoreOps vkStencilOps(loadOp, storeOp); 238 239 GrVkResourceProvider::CompatibleRPHandle rpHandle = fFramebuffer->compatibleRenderPassHandle(); 240 SkASSERT(rpHandle.isValid()); 241 fCurrentRenderPass = fGpu->resourceProvider().findRenderPass(rpHandle, 242 vkColorOps, 243 vkResolveOps, 244 vkStencilOps); 245 246 if (!fCurrentRenderPass) { 247 return false; 248 } 249 250 if (!fGpu->vkCaps().preferPrimaryOverSecondaryCommandBuffers()) { 251 SkASSERT(fGpu->cmdPool()); 252 fCurrentSecondaryCommandBuffer = fGpu->cmdPool()->findOrCreateSecondaryCommandBuffer(fGpu); 253 if (!fCurrentSecondaryCommandBuffer) { 254 fCurrentRenderPass = nullptr; 255 return false; 256 } 257 fCurrentSecondaryCommandBuffer->begin(fGpu, fFramebuffer.get(), fCurrentRenderPass); 258 } 259 260 VkClearValue vkClearColor; 261 vkClearColor.color.float32[0] = colorInfo.fClearColor[0]; 262 vkClearColor.color.float32[1] = colorInfo.fClearColor[1]; 263 vkClearColor.color.float32[2] = colorInfo.fClearColor[2]; 264 vkClearColor.color.float32[3] = colorInfo.fClearColor[3]; 265 266 return this->beginRenderPass(vkClearColor, fLoadFromResolve); 267} 268 269bool GrVkOpsRenderPass::initWrapped() { 270 SkASSERT(fFramebuffer->isExternal()); 271 fCurrentRenderPass = fFramebuffer->externalRenderPass(); 272 SkASSERT(fCurrentRenderPass); 273 fCurrentRenderPass->ref(); 274 275 fCurrentSecondaryCommandBuffer = fFramebuffer->externalCommandBuffer(); 276 if (!fCurrentSecondaryCommandBuffer) { 277 return false; 278 } 279 return true; 280} 281 282GrVkOpsRenderPass::~GrVkOpsRenderPass() { 283 this->reset(); 284} 285 286GrGpu* GrVkOpsRenderPass::gpu() { return fGpu; } 287 288GrVkCommandBuffer* GrVkOpsRenderPass::currentCommandBuffer() { 289 if (fCurrentSecondaryCommandBuffer) { 290 return fCurrentSecondaryCommandBuffer.get(); 291 } 292 // We checked this when we setup the GrVkOpsRenderPass and it should not have changed while we 293 // are still using this object. 294 SkASSERT(fGpu->currentCommandBuffer()); 295 return fGpu->currentCommandBuffer(); 296} 297 298void GrVkOpsRenderPass::loadResolveIntoMSAA(const SkIRect& nativeBounds) { 299 fGpu->loadMSAAFromResolve(this->currentCommandBuffer(), *fCurrentRenderPass, 300 fFramebuffer->colorAttachment(), fFramebuffer->resolveAttachment(), 301 nativeBounds); 302 fGpu->currentCommandBuffer()->nexSubpass(fGpu, SkToBool(fCurrentSecondaryCommandBuffer)); 303 304 // If we loaded the resolve attachment, then we would have set the image layout to be 305 // VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL so that it could be used at the start as an input 306 // attachment. However, when we switched to the main subpass it will transition the layout 307 // internally to VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL. Thus we need to update our tracking 308 // of the layout to match the new layout. 309 SkASSERT(fFramebuffer->resolveAttachment()); 310 fFramebuffer->resolveAttachment()->updateImageLayout(VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); 311} 312 313void GrVkOpsRenderPass::submit() { 314 if (!fRenderTarget) { 315 return; 316 } 317 if (!fCurrentRenderPass) { 318 SkASSERT(fGpu->isDeviceLost()); 319 return; 320 } 321 322 // We don't want to actually submit the secondary command buffer if it is wrapped. 323 if (this->wrapsSecondaryCommandBuffer()) { 324 // We pass the ownership of the GrVkSecondaryCommandBuffer to the external framebuffer 325 // since it's lifetime matches the lifetime we need to keep the GrManagedResources on the 326 // GrVkSecondaryCommandBuffer alive. 327 fFramebuffer->returnExternalGrSecondaryCommandBuffer( 328 std::move(fCurrentSecondaryCommandBuffer)); 329 return; 330 } 331 332 if (fCurrentSecondaryCommandBuffer) { 333 fGpu->submitSecondaryCommandBuffer(std::move(fCurrentSecondaryCommandBuffer)); 334 } 335 fGpu->endRenderPass(fRenderTarget, fOrigin, fBounds); 336} 337 338bool GrVkOpsRenderPass::set(GrRenderTarget* rt, 339 sk_sp<GrVkFramebuffer> framebuffer, 340 GrSurfaceOrigin origin, 341 const SkIRect& bounds, 342 const GrOpsRenderPass::LoadAndStoreInfo& colorInfo, 343 const GrOpsRenderPass::StencilLoadAndStoreInfo& stencilInfo, 344 const GrOpsRenderPass::LoadAndStoreInfo& resolveInfo, 345 GrVkRenderPass::SelfDependencyFlags selfDepFlags, 346 GrVkRenderPass::LoadFromResolve loadFromResolve, 347 const SkTArray<GrSurfaceProxy*, true>& sampledProxies) { 348 SkASSERT(!fRenderTarget); 349 SkASSERT(fGpu == rt->getContext()->priv().getGpu()); 350 351#ifdef SK_DEBUG 352 fIsActive = true; 353#endif 354 355 // We check to make sure the GrVkGpu has a valid current command buffer instead of each time we 356 // access it. If the command buffer is valid here should be valid throughout the use of the 357 // render pass since nothing should trigger a submit while this render pass is active. 358 if (!fGpu->currentCommandBuffer()) { 359 return false; 360 } 361 362 this->INHERITED::set(rt, origin); 363 364 for (int i = 0; i < sampledProxies.count(); ++i) { 365 if (sampledProxies[i]->isInstantiated()) { 366 SkASSERT(sampledProxies[i]->asTextureProxy()); 367 GrVkTexture* vkTex = static_cast<GrVkTexture*>(sampledProxies[i]->peekTexture()); 368 SkASSERT(vkTex); 369 GrVkImage* texture = vkTex->textureImage(); 370 SkASSERT(texture); 371 texture->setImageLayout( 372 fGpu, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_SHADER_READ_BIT, 373 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, false); 374 } 375 } 376 377 SkASSERT(framebuffer); 378 fFramebuffer = std::move(framebuffer); 379 380 SkASSERT(bounds.isEmpty() || 381 SkIRect::MakeSize(fFramebuffer->colorAttachment()->dimensions()).contains(bounds)); 382 fBounds = bounds; 383 384 fSelfDependencyFlags = selfDepFlags; 385 fLoadFromResolve = loadFromResolve; 386 387 if (this->wrapsSecondaryCommandBuffer()) { 388 return this->initWrapped(); 389 } 390 391 return this->init(colorInfo, resolveInfo, stencilInfo); 392} 393 394void GrVkOpsRenderPass::reset() { 395 if (fCurrentSecondaryCommandBuffer) { 396 // The active GrVkCommandPool on the GrVkGpu should still be the same pool we got the 397 // secondary command buffer from since we haven't submitted any work yet. 398 SkASSERT(fGpu->cmdPool()); 399 fCurrentSecondaryCommandBuffer.release()->recycle(fGpu->cmdPool()); 400 } 401 if (fCurrentRenderPass) { 402 fCurrentRenderPass->unref(); 403 fCurrentRenderPass = nullptr; 404 } 405 fCurrentCBIsEmpty = true; 406 407 fRenderTarget = nullptr; 408 fFramebuffer.reset(); 409 410 fSelfDependencyFlags = GrVkRenderPass::SelfDependencyFlags::kNone; 411 412 fLoadFromResolve = LoadFromResolve::kNo; 413 fOverridePipelinesForResolveLoad = false; 414 415#ifdef SK_DEBUG 416 fIsActive = false; 417#endif 418} 419 420bool GrVkOpsRenderPass::wrapsSecondaryCommandBuffer() const { 421 return fFramebuffer->isExternal(); 422} 423 424//////////////////////////////////////////////////////////////////////////////// 425 426void GrVkOpsRenderPass::onClearStencilClip(const GrScissorState& scissor, bool insideStencilMask) { 427 if (!fCurrentRenderPass) { 428 SkASSERT(fGpu->isDeviceLost()); 429 return; 430 } 431 432 GrAttachment* sb = fFramebuffer->stencilAttachment(); 433 // this should only be called internally when we know we have a 434 // stencil buffer. 435 SkASSERT(sb); 436 int stencilBitCount = GrBackendFormatStencilBits(sb->backendFormat()); 437 438 // The contract with the callers does not guarantee that we preserve all bits in the stencil 439 // during this clear. Thus we will clear the entire stencil to the desired value. 440 441 VkClearDepthStencilValue vkStencilColor; 442 memset(&vkStencilColor, 0, sizeof(VkClearDepthStencilValue)); 443 if (insideStencilMask) { 444 vkStencilColor.stencil = (1 << (stencilBitCount - 1)); 445 } else { 446 vkStencilColor.stencil = 0; 447 } 448 449 VkClearRect clearRect; 450 // Flip rect if necessary 451 SkIRect vkRect; 452 if (!scissor.enabled()) { 453 vkRect.setXYWH(0, 0, sb->width(), sb->height()); 454 } else if (kBottomLeft_GrSurfaceOrigin != fOrigin) { 455 vkRect = scissor.rect(); 456 } else { 457 vkRect.setLTRB(scissor.rect().fLeft, sb->height() - scissor.rect().fBottom, 458 scissor.rect().fRight, sb->height() - scissor.rect().fTop); 459 } 460 461 clearRect.rect.offset = { vkRect.fLeft, vkRect.fTop }; 462 clearRect.rect.extent = { (uint32_t)vkRect.width(), (uint32_t)vkRect.height() }; 463 464 clearRect.baseArrayLayer = 0; 465 clearRect.layerCount = 1; 466 467 uint32_t stencilIndex; 468 SkAssertResult(fCurrentRenderPass->stencilAttachmentIndex(&stencilIndex)); 469 470 VkClearAttachment attachment; 471 attachment.aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT; 472 attachment.colorAttachment = 0; // this value shouldn't matter 473 attachment.clearValue.depthStencil = vkStencilColor; 474 475 this->currentCommandBuffer()->clearAttachments(fGpu, 1, &attachment, 1, &clearRect); 476 fCurrentCBIsEmpty = false; 477} 478 479void GrVkOpsRenderPass::onClear(const GrScissorState& scissor, std::array<float, 4> color) { 480 if (!fCurrentRenderPass) { 481 SkASSERT(fGpu->isDeviceLost()); 482 return; 483 } 484 485 VkClearColorValue vkColor = {{color[0], color[1], color[2], color[3]}}; 486 487 // If we end up in a situation where we are calling clear without a scissior then in general it 488 // means we missed an opportunity higher up the stack to set the load op to be a clear. However, 489 // there are situations where higher up we couldn't discard the previous ops and set a clear 490 // load op (e.g. if we needed to execute a wait op). Thus we also have the empty check here. 491 // TODO: Make the waitOp a RenderTask instead so we can clear out the OpsTask for a clear. We 492 // can then reenable this assert assuming we can't get messed up by a waitOp. 493 //SkASSERT(!fCurrentCBIsEmpty || scissor); 494 495 auto dimensions = fFramebuffer->colorAttachment()->dimensions(); 496 // We always do a sub rect clear with clearAttachments since we are inside a render pass 497 VkClearRect clearRect; 498 // Flip rect if necessary 499 SkIRect vkRect; 500 if (!scissor.enabled()) { 501 vkRect.setSize(dimensions); 502 } else if (kBottomLeft_GrSurfaceOrigin != fOrigin) { 503 vkRect = scissor.rect(); 504 } else { 505 vkRect.setLTRB(scissor.rect().fLeft, dimensions.height() - scissor.rect().fBottom, 506 scissor.rect().fRight, dimensions.height() - scissor.rect().fTop); 507 } 508 clearRect.rect.offset = { vkRect.fLeft, vkRect.fTop }; 509 clearRect.rect.extent = { (uint32_t)vkRect.width(), (uint32_t)vkRect.height() }; 510 clearRect.baseArrayLayer = 0; 511 clearRect.layerCount = 1; 512 513 uint32_t colorIndex; 514 SkAssertResult(fCurrentRenderPass->colorAttachmentIndex(&colorIndex)); 515 516 VkClearAttachment attachment; 517 attachment.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; 518 attachment.colorAttachment = colorIndex; 519 attachment.clearValue.color = vkColor; 520 521 this->currentCommandBuffer()->clearAttachments(fGpu, 1, &attachment, 1, &clearRect); 522 fCurrentCBIsEmpty = false; 523 return; 524} 525 526//////////////////////////////////////////////////////////////////////////////// 527 528void GrVkOpsRenderPass::addAdditionalRenderPass(bool mustUseSecondaryCommandBuffer) { 529 SkASSERT(!this->wrapsSecondaryCommandBuffer()); 530 531 bool withResolve = fFramebuffer->resolveAttachment(); 532 bool withStencil = fFramebuffer->stencilAttachment(); 533 534 // If we have a resolve attachment we must do a resolve load in the new render pass since we 535 // broke up the original one. GrProgramInfos were made without any knowledge that the render 536 // pass may be split up. Thus they may try to make VkPipelines that only use one subpass. We 537 // need to override that to make sure they are compatible with the extra load subpass. 538 fOverridePipelinesForResolveLoad |= 539 withResolve && fCurrentRenderPass->loadFromResolve() != LoadFromResolve::kLoad; 540 541 GrVkRenderPass::LoadStoreOps vkColorOps(VK_ATTACHMENT_LOAD_OP_LOAD, 542 VK_ATTACHMENT_STORE_OP_STORE); 543 GrVkRenderPass::LoadStoreOps vkResolveOps(VK_ATTACHMENT_LOAD_OP_LOAD, 544 VK_ATTACHMENT_STORE_OP_STORE); 545 LoadFromResolve loadFromResolve = LoadFromResolve::kNo; 546 if (withResolve) { 547 vkColorOps = {VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE}; 548 loadFromResolve = LoadFromResolve::kLoad; 549 } 550 GrVkRenderPass::LoadStoreOps vkStencilOps(VK_ATTACHMENT_LOAD_OP_LOAD, 551 VK_ATTACHMENT_STORE_OP_STORE); 552 553 SkASSERT(fCurrentRenderPass); 554 fCurrentRenderPass->unref(); 555 fCurrentRenderPass = nullptr; 556 557 GrVkRenderTarget* vkRT = static_cast<GrVkRenderTarget*>(fRenderTarget); 558 auto fb = vkRT->getFramebuffer(withResolve, withStencil, fSelfDependencyFlags, loadFromResolve); 559 if (!fb) { 560 return; 561 } 562 fFramebuffer = sk_ref_sp(fb); 563 564 SkASSERT(fFramebuffer); 565 const GrVkResourceProvider::CompatibleRPHandle& rpHandle = 566 fFramebuffer->compatibleRenderPassHandle(); 567 SkASSERT(rpHandle.isValid()); 568 569 fCurrentRenderPass = fGpu->resourceProvider().findRenderPass(rpHandle, 570 vkColorOps, 571 vkResolveOps, 572 vkStencilOps); 573 574 if (!fCurrentRenderPass) { 575 return; 576 } 577 578 if (!fGpu->vkCaps().preferPrimaryOverSecondaryCommandBuffers() || 579 mustUseSecondaryCommandBuffer) { 580 SkASSERT(fGpu->cmdPool()); 581 fCurrentSecondaryCommandBuffer = fGpu->cmdPool()->findOrCreateSecondaryCommandBuffer(fGpu); 582 if (!fCurrentSecondaryCommandBuffer) { 583 fCurrentRenderPass = nullptr; 584 return; 585 } 586 fCurrentSecondaryCommandBuffer->begin(fGpu, fFramebuffer.get(), fCurrentRenderPass); 587 } 588 589 VkClearValue vkClearColor; 590 memset(&vkClearColor, 0, sizeof(VkClearValue)); 591 592 this->beginRenderPass(vkClearColor, loadFromResolve); 593} 594 595void GrVkOpsRenderPass::inlineUpload(GrOpFlushState* state, GrDeferredTextureUploadFn& upload) { 596 if (!fCurrentRenderPass) { 597 SkASSERT(fGpu->isDeviceLost()); 598 return; 599 } 600 if (fCurrentSecondaryCommandBuffer) { 601 fCurrentSecondaryCommandBuffer->end(fGpu); 602 fGpu->submitSecondaryCommandBuffer(std::move(fCurrentSecondaryCommandBuffer)); 603 } 604 fGpu->endRenderPass(fRenderTarget, fOrigin, fBounds); 605 606 // We pass in true here to signal that after the upload we need to set the upload textures 607 // layout back to VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL. 608 state->doUpload(upload, true); 609 610 this->addAdditionalRenderPass(false); 611} 612 613//////////////////////////////////////////////////////////////////////////////// 614 615void GrVkOpsRenderPass::onEnd() { 616 if (fCurrentSecondaryCommandBuffer && !this->wrapsSecondaryCommandBuffer()) { 617 fCurrentSecondaryCommandBuffer->end(fGpu); 618 } 619} 620 621bool GrVkOpsRenderPass::onBindPipeline(const GrProgramInfo& programInfo, const SkRect& drawBounds) { 622 if (!fCurrentRenderPass) { 623 SkASSERT(fGpu->isDeviceLost()); 624 return false; 625 } 626 627 SkRect rtRect = SkRect::Make(fBounds); 628 if (rtRect.intersect(drawBounds)) { 629 rtRect.roundOut(&fCurrentPipelineBounds); 630 } else { 631 fCurrentPipelineBounds.setEmpty(); 632 } 633 634 GrVkCommandBuffer* currentCB = this->currentCommandBuffer(); 635 SkASSERT(fCurrentRenderPass); 636 637 VkRenderPass compatibleRenderPass = fCurrentRenderPass->vkRenderPass(); 638 fCurrentPipelineState = fGpu->resourceProvider().findOrCreateCompatiblePipelineState( 639 fRenderTarget, programInfo, compatibleRenderPass, fOverridePipelinesForResolveLoad); 640 if (!fCurrentPipelineState) { 641 return false; 642 } 643 644 fCurrentPipelineState->bindPipeline(fGpu, currentCB); 645 646 // Both the 'programInfo' and this renderPass have an origin. Since they come from the 647 // same place (i.e., the target renderTargetProxy) they had best agree. 648 SkASSERT(programInfo.origin() == fOrigin); 649 650 auto colorAttachment = fFramebuffer->colorAttachment(); 651 if (!fCurrentPipelineState->setAndBindUniforms(fGpu, colorAttachment->dimensions(), programInfo, 652 currentCB)) { 653 return false; 654 } 655 656 if (!programInfo.pipeline().isScissorTestEnabled()) { 657 // "Disable" scissor by setting it to the full pipeline bounds. 658 GrVkPipeline::SetDynamicScissorRectState( 659 fGpu, currentCB, colorAttachment->dimensions(), fOrigin, 660 fCurrentPipelineBounds); 661 } 662 GrVkPipeline::SetDynamicViewportState(fGpu, currentCB, colorAttachment->dimensions()); 663 GrVkPipeline::SetDynamicBlendConstantState(fGpu, currentCB, 664 programInfo.pipeline().writeSwizzle(), 665 programInfo.pipeline().getXferProcessor()); 666 667 return true; 668} 669 670void GrVkOpsRenderPass::onSetScissorRect(const SkIRect& scissor) { 671 SkIRect combinedScissorRect; 672 if (!combinedScissorRect.intersect(fCurrentPipelineBounds, scissor)) { 673 combinedScissorRect = SkIRect::MakeEmpty(); 674 } 675 GrVkPipeline::SetDynamicScissorRectState(fGpu, this->currentCommandBuffer(), 676 fFramebuffer->colorAttachment()->dimensions(), 677 fOrigin, combinedScissorRect); 678} 679 680#ifdef SK_DEBUG 681void check_sampled_texture(GrTexture* tex, GrAttachment* colorAttachment, GrVkGpu* gpu) { 682 SkASSERT(!tex->isProtected() || (colorAttachment->isProtected() && gpu->protectedContext())); 683 auto vkTex = static_cast<GrVkTexture*>(tex)->textureImage(); 684 SkASSERT(vkTex->currentLayout() == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); 685} 686#endif 687 688bool GrVkOpsRenderPass::onBindTextures(const GrGeometryProcessor& geomProc, 689 const GrSurfaceProxy* const geomProcTextures[], 690 const GrPipeline& pipeline) { 691#ifdef SK_DEBUG 692 SkASSERT(fCurrentPipelineState); 693 auto colorAttachment = fFramebuffer->colorAttachment(); 694 for (int i = 0; i < geomProc.numTextureSamplers(); ++i) { 695 check_sampled_texture(geomProcTextures[i]->peekTexture(), colorAttachment, fGpu); 696 } 697 pipeline.visitTextureEffects([&](const GrTextureEffect& te) { 698 check_sampled_texture(te.texture(), colorAttachment, fGpu); 699 }); 700 if (GrTexture* dstTexture = pipeline.peekDstTexture()) { 701 check_sampled_texture(dstTexture, colorAttachment, fGpu); 702 } 703#endif 704 if (!fCurrentPipelineState->setAndBindTextures(fGpu, geomProc, pipeline, geomProcTextures, 705 this->currentCommandBuffer())) { 706 return false; 707 } 708 if (fSelfDependencyFlags == SelfDependencyFlags::kForInputAttachment) { 709 // We bind the color attachment as an input attachment 710 auto ds = fFramebuffer->colorAttachment()->inputDescSetForBlending(fGpu); 711 if (!ds) { 712 return false; 713 } 714 return fCurrentPipelineState->setAndBindInputAttachment(fGpu, std::move(ds), 715 this->currentCommandBuffer()); 716 } 717 return true; 718} 719 720void GrVkOpsRenderPass::onBindBuffers(sk_sp<const GrBuffer> indexBuffer, 721 sk_sp<const GrBuffer> instanceBuffer, 722 sk_sp<const GrBuffer> vertexBuffer, 723 GrPrimitiveRestart primRestart) { 724 SkASSERT(GrPrimitiveRestart::kNo == primRestart); 725 if (!fCurrentRenderPass) { 726 SkASSERT(fGpu->isDeviceLost()); 727 return; 728 } 729 SkASSERT(fCurrentPipelineState); 730 SkASSERT(!fGpu->caps()->usePrimitiveRestart()); // Ignore primitiveRestart parameter. 731 732 GrVkCommandBuffer* currCmdBuf = this->currentCommandBuffer(); 733 SkASSERT(currCmdBuf); 734 735 // There is no need to put any memory barriers to make sure host writes have finished here. 736 // When a command buffer is submitted to a queue, there is an implicit memory barrier that 737 // occurs for all host writes. Additionally, BufferMemoryBarriers are not allowed inside of 738 // an active RenderPass. 739 740 // Here our vertex and instance inputs need to match the same 0-based bindings they were 741 // assigned in GrVkPipeline. That is, vertex first (if any) followed by instance. 742 uint32_t binding = 0; 743 if (auto* gpuVertexBuffer = static_cast<const GrGpuBuffer*>(vertexBuffer.get())) { 744 SkASSERT(!gpuVertexBuffer->isCpuBuffer()); 745 SkASSERT(!gpuVertexBuffer->isMapped()); 746 currCmdBuf->bindInputBuffer(fGpu, binding++, std::move(vertexBuffer)); 747 } 748 if (auto* gpuInstanceBuffer = static_cast<const GrGpuBuffer*>(instanceBuffer.get())) { 749 SkASSERT(!gpuInstanceBuffer->isCpuBuffer()); 750 SkASSERT(!gpuInstanceBuffer->isMapped()); 751 currCmdBuf->bindInputBuffer(fGpu, binding++, std::move(instanceBuffer)); 752 } 753 if (auto* gpuIndexBuffer = static_cast<const GrGpuBuffer*>(indexBuffer.get())) { 754 SkASSERT(!gpuIndexBuffer->isCpuBuffer()); 755 SkASSERT(!gpuIndexBuffer->isMapped()); 756 currCmdBuf->bindIndexBuffer(fGpu, std::move(indexBuffer)); 757 } 758} 759 760void GrVkOpsRenderPass::onDrawInstanced(int instanceCount, 761 int baseInstance, 762 int vertexCount, int baseVertex) { 763 if (!fCurrentRenderPass) { 764 SkASSERT(fGpu->isDeviceLost()); 765 return; 766 } 767 SkASSERT(fCurrentPipelineState); 768 this->currentCommandBuffer()->draw(fGpu, vertexCount, instanceCount, baseVertex, baseInstance); 769 fGpu->stats()->incNumDraws(); 770 fCurrentCBIsEmpty = false; 771} 772 773void GrVkOpsRenderPass::onDrawIndexedInstanced(int indexCount, int baseIndex, int instanceCount, 774 int baseInstance, int baseVertex) { 775 if (!fCurrentRenderPass) { 776 SkASSERT(fGpu->isDeviceLost()); 777 return; 778 } 779 SkASSERT(fCurrentPipelineState); 780 this->currentCommandBuffer()->drawIndexed(fGpu, indexCount, instanceCount, 781 baseIndex, baseVertex, baseInstance); 782 fGpu->stats()->incNumDraws(); 783 fCurrentCBIsEmpty = false; 784} 785 786void GrVkOpsRenderPass::onDrawIndirect(const GrBuffer* drawIndirectBuffer, size_t offset, 787 int drawCount) { 788 SkASSERT(!drawIndirectBuffer->isCpuBuffer()); 789 if (!fCurrentRenderPass) { 790 SkASSERT(fGpu->isDeviceLost()); 791 return; 792 } 793 const GrVkCaps& caps = fGpu->vkCaps(); 794 SkASSERT(caps.nativeDrawIndirectSupport()); 795 SkASSERT(fCurrentPipelineState); 796 797 const uint32_t maxDrawCount = caps.maxDrawIndirectDrawCount(); 798 uint32_t remainingDraws = drawCount; 799 const size_t stride = sizeof(GrDrawIndirectCommand); 800 while (remainingDraws >= 1) { 801 uint32_t currDrawCount = std::min(remainingDraws, maxDrawCount); 802 this->currentCommandBuffer()->drawIndirect( 803 fGpu, sk_ref_sp(drawIndirectBuffer), offset, currDrawCount, stride); 804 remainingDraws -= currDrawCount; 805 offset += stride * currDrawCount; 806 fGpu->stats()->incNumDraws(); 807 } 808 fCurrentCBIsEmpty = false; 809} 810 811void GrVkOpsRenderPass::onDrawIndexedIndirect(const GrBuffer* drawIndirectBuffer, size_t offset, 812 int drawCount) { 813 SkASSERT(!drawIndirectBuffer->isCpuBuffer()); 814 if (!fCurrentRenderPass) { 815 SkASSERT(fGpu->isDeviceLost()); 816 return; 817 } 818 const GrVkCaps& caps = fGpu->vkCaps(); 819 SkASSERT(caps.nativeDrawIndirectSupport()); 820 SkASSERT(fCurrentPipelineState); 821 const uint32_t maxDrawCount = caps.maxDrawIndirectDrawCount(); 822 uint32_t remainingDraws = drawCount; 823 const size_t stride = sizeof(GrDrawIndexedIndirectCommand); 824 while (remainingDraws >= 1) { 825 uint32_t currDrawCount = std::min(remainingDraws, maxDrawCount); 826 this->currentCommandBuffer()->drawIndexedIndirect( 827 fGpu, sk_ref_sp(drawIndirectBuffer), offset, currDrawCount, stride); 828 remainingDraws -= currDrawCount; 829 offset += stride * currDrawCount; 830 fGpu->stats()->incNumDraws(); 831 } 832 fCurrentCBIsEmpty = false; 833} 834 835//////////////////////////////////////////////////////////////////////////////// 836 837void GrVkOpsRenderPass::onExecuteDrawable(std::unique_ptr<SkDrawable::GpuDrawHandler> drawable) { 838 if (!fCurrentRenderPass) { 839 SkASSERT(fGpu->isDeviceLost()); 840 return; 841 } 842 843 VkRect2D bounds; 844 bounds.offset = { 0, 0 }; 845 bounds.extent = { 0, 0 }; 846 847 if (!fCurrentSecondaryCommandBuffer) { 848 fGpu->endRenderPass(fRenderTarget, fOrigin, fBounds); 849 this->addAdditionalRenderPass(true); 850 // We may have failed to start a new render pass 851 if (!fCurrentRenderPass) { 852 SkASSERT(fGpu->isDeviceLost()); 853 return; 854 } 855 } 856 SkASSERT(fCurrentSecondaryCommandBuffer); 857 858 GrVkDrawableInfo vkInfo; 859 vkInfo.fSecondaryCommandBuffer = fCurrentSecondaryCommandBuffer->vkCommandBuffer(); 860 vkInfo.fCompatibleRenderPass = fCurrentRenderPass->vkRenderPass(); 861 SkAssertResult(fCurrentRenderPass->colorAttachmentIndex(&vkInfo.fColorAttachmentIndex)); 862 vkInfo.fFormat = fFramebuffer->colorAttachment()->imageFormat(); 863 vkInfo.fDrawBounds = &bounds; 864#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK 865 vkInfo.fImage = fFramebuffer->colorAttachment()->image(); 866#else 867 vkInfo.fImage = VK_NULL_HANDLE; 868#endif //SK_BUILD_FOR_ANDROID_FRAMEWORK 869 870 GrBackendDrawableInfo info(vkInfo); 871 872 // After we draw into the command buffer via the drawable, cached state we have may be invalid. 873 this->currentCommandBuffer()->invalidateState(); 874 // Also assume that the drawable produced output. 875 fCurrentCBIsEmpty = false; 876 877 drawable->draw(info); 878 fGpu->addDrawable(std::move(drawable)); 879} 880 881 882//////////////////////////////////////////////////////////////////////////////// 883 884void GrVkOpsRenderPass::onDrawBlurImage(const GrSurfaceProxyView& proxyView, const SkBlurArg& blurArg) 885{ 886 if (!proxyView.proxy()) { 887 return; 888 } 889 890 GrVkTexture* texture = static_cast<GrVkTexture*>(proxyView.proxy()->peekTexture()); 891 if (!texture) { 892 return; 893 } 894 GrVkImage* image = texture->textureImage(); 895 if (!image) { 896 return; 897 } 898 899 HITRACE_OHOS_NAME_ALWAYS("DrawBlurImage"); 900 // reference textureop, resource's refcount should add. 901 fGpu->currentCommandBuffer()->addResource(image->textureView()); 902 fGpu->currentCommandBuffer()->addResource(image->resource()); 903 // OH ISSUE : fix hps blur, add GrSurface reference protection 904 fGpu->currentCommandBuffer()->addGrSurface(sk_ref_sp<const GrSurface>(texture)); 905 SkOriginInfo originInfo {}; 906 originInfo.imageOrigin = proxyView.origin(); 907 originInfo.rtOrigin = fOrigin; 908 fGpu->currentCommandBuffer()->drawBlurImage(fGpu, image, fFramebuffer->colorAttachment()->dimensions(), 909 originInfo, blurArg); 910 return; 911} 912