/*
* Copyright 2015 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "GrVkRenderPass.h"
#include "GrProcessor.h"
#include "GrVkFramebuffer.h"
#include "GrVkGpu.h"
#include "GrVkRenderTarget.h"
#include "GrVkUtil.h"
typedef GrVkRenderPass::AttachmentsDescriptor::AttachmentDesc AttachmentDesc;
void setup_vk_attachment_description(VkAttachmentDescription* attachment,
const AttachmentDesc& desc,
VkImageLayout layout) {
attachment->flags = 0;
attachment->format = desc.fFormat;
SkAssertResult(GrSampleCountToVkSampleCount(desc.fSamples, &attachment->samples));
switch (layout) {
case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
attachment->loadOp = desc.fLoadStoreOps.fLoadOp;
attachment->storeOp = desc.fLoadStoreOps.fStoreOp;
attachment->stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
attachment->stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
break;
case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:
attachment->loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
attachment->storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
attachment->stencilLoadOp = desc.fLoadStoreOps.fLoadOp;
attachment->stencilStoreOp = desc.fLoadStoreOps.fStoreOp;
break;
default:
SK_ABORT("Unexpected attachment layout");
}
attachment->initialLayout = layout;
attachment->finalLayout = layout;
}
void GrVkRenderPass::initSimple(const GrVkGpu* gpu, const GrVkRenderTarget& target) {
static const GrVkRenderPass::LoadStoreOps kBasicLoadStoreOps(VK_ATTACHMENT_LOAD_OP_LOAD,
VK_ATTACHMENT_STORE_OP_STORE);
this->init(gpu, target, kBasicLoadStoreOps, kBasicLoadStoreOps);
}
void GrVkRenderPass::init(const GrVkGpu* gpu,
const LoadStoreOps& colorOp,
const LoadStoreOps& stencilOp) {
uint32_t numAttachments = fAttachmentsDescriptor.fAttachmentCount;
// Attachment descriptions to be set on the render pass
SkTArray<VkAttachmentDescription> attachments(numAttachments);
attachments.reset(numAttachments);
memset(attachments.begin(), 0, numAttachments * sizeof(VkAttachmentDescription));
// Refs to attachments on the render pass (as described by teh VkAttachmentDescription above),
// that are used by the subpass.
VkAttachmentReference colorRef;
VkAttachmentReference stencilRef;
uint32_t currentAttachment = 0;
// Go through each of the attachment types (color, stencil) and set the necessary
// on the various Vk structs.
VkSubpassDescription subpassDesc;
memset(&subpassDesc, 0, sizeof(VkSubpassDescription));
subpassDesc.flags = 0;
subpassDesc.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
subpassDesc.inputAttachmentCount = 0;
subpassDesc.pInputAttachments = nullptr;
subpassDesc.pResolveAttachments = nullptr;
if (fAttachmentFlags & kColor_AttachmentFlag) {
// set up color attachment
fAttachmentsDescriptor.fColor.fLoadStoreOps = colorOp;
setup_vk_attachment_description(&attachments[currentAttachment],
fAttachmentsDescriptor.fColor,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
// setup subpass use of attachment
colorRef.attachment = currentAttachment++;
colorRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
subpassDesc.colorAttachmentCount = 1;
if (VK_ATTACHMENT_LOAD_OP_CLEAR == colorOp.fLoadOp) {
fClearValueCount = colorRef.attachment + 1;
}
} else {
// I don't think there should ever be a time where we don't have a color attachment
SkASSERT(false);
colorRef.attachment = VK_ATTACHMENT_UNUSED;
colorRef.layout = VK_IMAGE_LAYOUT_UNDEFINED;
subpassDesc.colorAttachmentCount = 0;
}
subpassDesc.pColorAttachments = &colorRef;
if (fAttachmentFlags & kStencil_AttachmentFlag) {
// set up stencil attachment
fAttachmentsDescriptor.fStencil.fLoadStoreOps = stencilOp;
setup_vk_attachment_description(&attachments[currentAttachment],
fAttachmentsDescriptor.fStencil,
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
// setup subpass use of attachment
stencilRef.attachment = currentAttachment++;
stencilRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
if (VK_ATTACHMENT_LOAD_OP_CLEAR == stencilOp.fLoadOp) {
fClearValueCount = SkTMax(fClearValueCount, stencilRef.attachment + 1);
}
} else {
stencilRef.attachment = VK_ATTACHMENT_UNUSED;
stencilRef.layout = VK_IMAGE_LAYOUT_UNDEFINED;
}
subpassDesc.pDepthStencilAttachment = &stencilRef;
subpassDesc.preserveAttachmentCount = 0;
subpassDesc.pPreserveAttachments = nullptr;
SkASSERT(numAttachments == currentAttachment);
// Create the VkRenderPass compatible with the attachment descriptions above
VkRenderPassCreateInfo createInfo;
memset(&createInfo, 0, sizeof(VkRenderPassCreateInfo));
createInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
createInfo.pNext = nullptr;
createInfo.flags = 0;
createInfo.attachmentCount = numAttachments;
createInfo.pAttachments = attachments.begin();
createInfo.subpassCount = 1;
createInfo.pSubpasses = &subpassDesc;
createInfo.dependencyCount = 0;
createInfo.pDependencies = nullptr;
GR_VK_CALL_ERRCHECK(gpu->vkInterface(), CreateRenderPass(gpu->device(),
&createInfo,
nullptr,
&fRenderPass));
// Get granularity for this render pass
GR_VK_CALL(gpu->vkInterface(), GetRenderAreaGranularity(gpu->device(),
fRenderPass,
&fGranularity));
}
void GrVkRenderPass::init(const GrVkGpu* gpu,
const GrVkRenderPass& compatibleRenderPass,
const LoadStoreOps& colorOp,
const LoadStoreOps& stencilOp) {
fAttachmentFlags = compatibleRenderPass.fAttachmentFlags;
fAttachmentsDescriptor = compatibleRenderPass.fAttachmentsDescriptor;
this->init(gpu, colorOp, stencilOp);
}
void GrVkRenderPass::init(const GrVkGpu* gpu,
const GrVkRenderTarget& target,
const LoadStoreOps& colorOp,
const LoadStoreOps& stencilOp) {
// Get attachment information from render target. This includes which attachments the render
// target has (color, stencil) and the attachments format and sample count.
target.getAttachmentsDescriptor(&fAttachmentsDescriptor, &fAttachmentFlags);
this->init(gpu, colorOp, stencilOp);
}
void GrVkRenderPass::freeGPUData(const GrVkGpu* gpu) const {
GR_VK_CALL(gpu->vkInterface(), DestroyRenderPass(gpu->device(), fRenderPass, nullptr));
}
// Works under the assumption that color attachment will always be the first attachment in our
// attachment array if it exists.
bool GrVkRenderPass::colorAttachmentIndex(uint32_t* index) const {
*index = 0;
if (fAttachmentFlags & kColor_AttachmentFlag) {
return true;
}
return false;
}
// Works under the assumption that stencil attachment will always be after the color and resolve
// attachment.
bool GrVkRenderPass::stencilAttachmentIndex(uint32_t* index) const {
*index = 0;
if (fAttachmentFlags & kColor_AttachmentFlag) {
++(*index);
}
if (fAttachmentFlags & kStencil_AttachmentFlag) {
return true;
}
return false;
}
bool GrVkRenderPass::isCompatible(const AttachmentsDescriptor& desc,
const AttachmentFlags& flags) const {
if (flags != fAttachmentFlags) {
return false;
}
if (fAttachmentFlags & kColor_AttachmentFlag) {
if (!fAttachmentsDescriptor.fColor.isCompatible(desc.fColor)) {
return false;
}
}
if (fAttachmentFlags & kStencil_AttachmentFlag) {
if (!fAttachmentsDescriptor.fStencil.isCompatible(desc.fStencil)) {
return false;
}
}
return true;
}
bool GrVkRenderPass::isCompatible(const GrVkRenderTarget& target) const {
AttachmentsDescriptor desc;
AttachmentFlags flags;
target.getAttachmentsDescriptor(&desc, &flags);
return this->isCompatible(desc, flags);
}
bool GrVkRenderPass::isCompatible(const GrVkRenderPass& renderPass) const {
return this->isCompatible(renderPass.fAttachmentsDescriptor, renderPass.fAttachmentFlags);
}
bool GrVkRenderPass::equalLoadStoreOps(const LoadStoreOps& colorOps,
const LoadStoreOps& stencilOps) const {
if (fAttachmentFlags & kColor_AttachmentFlag) {
if (fAttachmentsDescriptor.fColor.fLoadStoreOps != colorOps) {
return false;
}
}
if (fAttachmentFlags & kStencil_AttachmentFlag) {
if (fAttachmentsDescriptor.fStencil.fLoadStoreOps != stencilOps) {
return false;
}
}
return true;
}
void GrVkRenderPass::genKey(GrProcessorKeyBuilder* b) const {
b->add32(fAttachmentFlags);
if (fAttachmentFlags & kColor_AttachmentFlag) {
b->add32(fAttachmentsDescriptor.fColor.fFormat);
b->add32(fAttachmentsDescriptor.fColor.fSamples);
}
if (fAttachmentFlags & kStencil_AttachmentFlag) {
b->add32(fAttachmentsDescriptor.fStencil.fFormat);
b->add32(fAttachmentsDescriptor.fStencil.fSamples);
}
}