C++程序  |  392行  |  14.44 KB

/*
 * 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 "GrVkRenderTarget.h"

#include "GrRenderTargetPriv.h"
#include "GrVkCommandBuffer.h"
#include "GrVkFramebuffer.h"
#include "GrVkGpu.h"
#include "GrVkImageView.h"
#include "GrVkResourceProvider.h"
#include "GrVkUtil.h"

#define VK_CALL(GPU, X) GR_VK_CALL(GPU->vkInterface(), X)

// We're virtually derived from GrSurface (via GrRenderTarget) so its
// constructor must be explicitly called.
GrVkRenderTarget::GrVkRenderTarget(GrVkGpu* gpu,
                                   const GrSurfaceDesc& desc,
                                   GrGpuResource::LifeCycle lifeCycle,
                                   const GrVkImage::Resource* imageResource,
                                   const GrVkImage::Resource* msaaResource,
                                   const GrVkImageView* colorAttachmentView,
                                   const GrVkImageView* resolveAttachmentView)
    : GrSurface(gpu, lifeCycle, desc)
    , GrVkImage(imageResource)
    // for the moment we only support 1:1 color to stencil
    , GrRenderTarget(gpu, lifeCycle, desc, kUnified_SampleConfig)
    , fFramebuffer(nullptr)
    , fColorAttachmentView(colorAttachmentView)
    , fMSAAImageResource(msaaResource)
    , fResolveAttachmentView(resolveAttachmentView)
    , fCachedSimpleRenderPass(nullptr) {
    SkASSERT(desc.fSampleCnt);
    // The plus 1 is to account for the resolve texture.
    fColorValuesPerPixel = desc.fSampleCnt + 1; // TODO: this still correct?
    this->createFramebuffer(gpu);
    this->registerWithCache();
    msaaResource->ref();
}

// We're virtually derived from GrSurface (via GrRenderTarget) so its
// constructor must be explicitly called.
GrVkRenderTarget::GrVkRenderTarget(GrVkGpu* gpu,
                                   const GrSurfaceDesc& desc,
                                   GrGpuResource::LifeCycle lifeCycle,
                                   const GrVkImage::Resource* imageResource,
                                   const GrVkImage::Resource* msaaResource,
                                   const GrVkImageView* colorAttachmentView,
                                   const GrVkImageView* resolveAttachmentView,
                                   Derived)
    : GrSurface(gpu, lifeCycle, desc)
    , GrVkImage(imageResource)
    // for the moment we only support 1:1 color to stencil
    , GrRenderTarget(gpu, lifeCycle, desc, kUnified_SampleConfig)
    , fFramebuffer(nullptr)
    , fColorAttachmentView(colorAttachmentView)
    , fMSAAImageResource(msaaResource)
    , fResolveAttachmentView(resolveAttachmentView)
    , fCachedSimpleRenderPass(nullptr) {
    SkASSERT(desc.fSampleCnt);
    // The plus 1 is to account for the resolve texture.
    fColorValuesPerPixel = desc.fSampleCnt + 1; // TODO: this still correct?
    this->createFramebuffer(gpu);
    msaaResource->ref();
}

// We're virtually derived from GrSurface (via GrRenderTarget) so its
// constructor must be explicitly called.
GrVkRenderTarget::GrVkRenderTarget(GrVkGpu* gpu,
                                   const GrSurfaceDesc& desc,
                                   GrGpuResource::LifeCycle lifeCycle,
                                   const GrVkImage::Resource* imageResource,
                                   const GrVkImageView* colorAttachmentView)
    : GrSurface(gpu, lifeCycle, desc)
    , GrVkImage(imageResource)
    , GrRenderTarget(gpu, lifeCycle, desc, kUnified_SampleConfig)
    , fFramebuffer(nullptr)
    , fColorAttachmentView(colorAttachmentView)
    , fMSAAImageResource(nullptr)
    , fResolveAttachmentView(nullptr)
    , fCachedSimpleRenderPass(nullptr) {
    SkASSERT(!desc.fSampleCnt);
    fColorValuesPerPixel = 1;
    this->createFramebuffer(gpu);
    this->registerWithCache();
}

// We're virtually derived from GrSurface (via GrRenderTarget) so its
// constructor must be explicitly called.
GrVkRenderTarget::GrVkRenderTarget(GrVkGpu* gpu,
                                   const GrSurfaceDesc& desc,
                                   GrGpuResource::LifeCycle lifeCycle,
                                   const GrVkImage::Resource* imageResource,
                                   const GrVkImageView* colorAttachmentView,
                                   Derived)
    : GrSurface(gpu, lifeCycle, desc)
    , GrVkImage(imageResource)
    , GrRenderTarget(gpu, lifeCycle, desc, kUnified_SampleConfig)
    , fFramebuffer(nullptr)
    , fColorAttachmentView(colorAttachmentView)
    , fMSAAImageResource(nullptr)
    , fResolveAttachmentView(nullptr)
    , fCachedSimpleRenderPass(nullptr) {
    SkASSERT(!desc.fSampleCnt);
    fColorValuesPerPixel = 1;
    this->createFramebuffer(gpu);
}

GrVkRenderTarget*
GrVkRenderTarget::Create(GrVkGpu* gpu,
                         const GrSurfaceDesc& desc,
                         GrGpuResource::LifeCycle lifeCycle,
                         const GrVkImage::Resource* imageResource) {
    VkFormat pixelFormat;
    GrPixelConfigToVkFormat(desc.fConfig, &pixelFormat);
    
    VkImage colorImage;

    // create msaa surface if necessary
    const GrVkImage::Resource* msaaResource = nullptr;
    const GrVkImageView* resolveAttachmentView = nullptr;
    if (desc.fSampleCnt) {
        GrVkImage::ImageDesc msImageDesc;
        msImageDesc.fImageType = VK_IMAGE_TYPE_2D;
        msImageDesc.fFormat = pixelFormat;
        msImageDesc.fWidth = desc.fWidth;
        msImageDesc.fHeight = desc.fHeight;
        msImageDesc.fLevels = 1;
        msImageDesc.fSamples = desc.fSampleCnt;
        msImageDesc.fImageTiling = VK_IMAGE_TILING_OPTIMAL;
        msImageDesc.fUsageFlags = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
        msImageDesc.fMemProps = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;

        msaaResource = GrVkImage::CreateResource(gpu, msImageDesc);

        if (!msaaResource) {
            return nullptr;
        }

        // Set color attachment image
        colorImage = msaaResource->fImage;

        // Create Resolve attachment view
        resolveAttachmentView = GrVkImageView::Create(gpu, imageResource->fImage, pixelFormat,
                                                      GrVkImageView::kColor_Type);
        if (!resolveAttachmentView) {
            msaaResource->unref(gpu);
            return nullptr;
        }
    } else {
        // Set color attachment image
        colorImage = imageResource->fImage;
    }

    // Get color attachment view
    const GrVkImageView* colorAttachmentView = GrVkImageView::Create(gpu, colorImage, pixelFormat,
                                                                     GrVkImageView::kColor_Type);
    if (!colorAttachmentView) {
        if (msaaResource) {
            resolveAttachmentView->unref(gpu);
            msaaResource->unref(gpu);
        }
        return NULL;
    }

    GrVkRenderTarget* texRT;
    if (msaaResource) {
        texRT = new GrVkRenderTarget(gpu, desc, lifeCycle, imageResource, msaaResource,
                                     colorAttachmentView, resolveAttachmentView);
        msaaResource->unref(gpu);
    } else {
        texRT = new GrVkRenderTarget(gpu, desc, lifeCycle, imageResource,
                                     colorAttachmentView);
    }

    return texRT;
}

GrVkRenderTarget*
GrVkRenderTarget::CreateNewRenderTarget(GrVkGpu* gpu,
                                        const GrSurfaceDesc& desc,
                                        GrGpuResource::LifeCycle lifeCycle,
                                        const GrVkImage::ImageDesc& imageDesc) {
    SkASSERT(imageDesc.fUsageFlags & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);

    const GrVkImage::Resource* imageResource = GrVkImage::CreateResource(gpu, imageDesc);
    if (!imageResource) {
        return nullptr;
    }

    GrVkRenderTarget* rt = GrVkRenderTarget::Create(gpu, desc, lifeCycle, imageResource);
    // Create() will increment the refCount of the image resource if it succeeds
    imageResource->unref(gpu);

    return rt;
}

GrVkRenderTarget*
GrVkRenderTarget::CreateWrappedRenderTarget(GrVkGpu* gpu,
                                            const GrSurfaceDesc& desc,
                                            GrGpuResource::LifeCycle lifeCycle,
                                            const GrVkImage::Resource* imageResource) {
    SkASSERT(imageResource);

    // Note: we assume the caller will unref the imageResource
    // Create() will increment the refCount, and we'll unref when we're done with it
    return GrVkRenderTarget::Create(gpu, desc, lifeCycle, imageResource);
}

bool GrVkRenderTarget::completeStencilAttachment() {
    this->createFramebuffer(this->getVkGpu());
    return true;
}

void GrVkRenderTarget::createFramebuffer(GrVkGpu* gpu) {
    if (fFramebuffer) {
        fFramebuffer->unref(gpu);
    }
    if (fCachedSimpleRenderPass) {
        fCachedSimpleRenderPass->unref(gpu);
    }

    // Vulkan requires us to create a compatible renderpass before we can create our framebuffer,
    // so we use this to get a (cached) basic renderpass, only for creation.
    fCachedSimpleRenderPass = gpu->resourceProvider().findOrCreateCompatibleRenderPass(*this);

    // Stencil attachment view is stored in the base RT stencil attachment
    const GrVkImageView* stencilView = this->stencilAttachmentView();
    fFramebuffer = GrVkFramebuffer::Create(gpu, this->width(), this->height(),
                                           fCachedSimpleRenderPass, fColorAttachmentView,
                                           fResolveAttachmentView, stencilView);
    SkASSERT(fFramebuffer);
}

void GrVkRenderTarget::getAttachmentsDescriptor(
                                           GrVkRenderPass::AttachmentsDescriptor* desc,
                                           GrVkRenderPass::AttachmentFlags* attachmentFlags) const {
    int colorSamples = this->numColorSamples();
    VkFormat colorFormat;
    GrPixelConfigToVkFormat(this->config(), &colorFormat);
    desc->fColor.fFormat = colorFormat;
    desc->fColor.fSamples = colorSamples ? colorSamples : 1;
    *attachmentFlags = GrVkRenderPass::kColor_AttachmentFlag;
    uint32_t attachmentCount = 1;
    if (colorSamples > 0) {
        desc->fResolve.fFormat = colorFormat;
        desc->fResolve.fSamples = 1;
        *attachmentFlags |= GrVkRenderPass::kResolve_AttachmentFlag;
        ++attachmentCount;
    }

    const GrStencilAttachment* stencil = this->renderTargetPriv().getStencilAttachment();
    if (stencil) {
        const GrVkStencilAttachment* vkStencil = static_cast<const GrVkStencilAttachment*>(stencil);
        desc->fStencil.fFormat = vkStencil->vkFormat();
        desc->fStencil.fSamples = vkStencil->numSamples() ? vkStencil->numSamples() : 1;
        // Currently in vulkan stencil and color attachments must all have same number of samples
        SkASSERT(desc->fColor.fSamples == desc->fStencil.fSamples);
        *attachmentFlags |= GrVkRenderPass::kStencil_AttachmentFlag;
        ++attachmentCount;
    }
    desc->fAttachmentCount = attachmentCount;
}

GrVkRenderTarget::~GrVkRenderTarget() {
    // either release or abandon should have been called by the owner of this object.
    SkASSERT(!fMSAAImageResource);
    SkASSERT(!fResolveAttachmentView);
    SkASSERT(!fColorAttachmentView);
    SkASSERT(!fFramebuffer);
    SkASSERT(!fCachedSimpleRenderPass);
}

void GrVkRenderTarget::addResources(GrVkCommandBuffer& commandBuffer) const {
    commandBuffer.addResource(this->framebuffer());
    commandBuffer.addResource(this->resource());
    commandBuffer.addResource(this->colorAttachmentView());
    if (this->msaaImageResource()) {
        commandBuffer.addResource(this->msaaImageResource());
        commandBuffer.addResource(this->resolveAttachmentView());
    }
    if (this->stencilImageResource()) {
        commandBuffer.addResource(this->stencilImageResource());
        commandBuffer.addResource(this->stencilAttachmentView());
    }
}

void GrVkRenderTarget::releaseInternalObjects() {
    GrVkGpu* gpu = this->getVkGpu();

    if (fMSAAImageResource) {
        fMSAAImageResource->unref(gpu);
        fMSAAImageResource = nullptr;
    }

    if (fResolveAttachmentView) {
        fResolveAttachmentView->unref(gpu);
        fResolveAttachmentView = nullptr;
    }
    if (fColorAttachmentView) {
        fColorAttachmentView->unref(gpu);
        fColorAttachmentView = nullptr;
    }
    if (fFramebuffer) {
        fFramebuffer->unref(gpu);
        fFramebuffer = nullptr;
    }
    if (fCachedSimpleRenderPass) {
        fCachedSimpleRenderPass->unref(gpu);
        fCachedSimpleRenderPass = nullptr;
    }
}

void GrVkRenderTarget::abandonInternalObjects() {
    if (fMSAAImageResource) {
        fMSAAImageResource->unrefAndAbandon();
        fMSAAImageResource = nullptr;
    }

    if (fResolveAttachmentView) {
        fResolveAttachmentView->unrefAndAbandon();
        fResolveAttachmentView = nullptr;
    }
    if (fColorAttachmentView) {
        fColorAttachmentView->unrefAndAbandon();
        fColorAttachmentView = nullptr;
    }
    if (fFramebuffer) {
        fFramebuffer->unrefAndAbandon();
        fFramebuffer = nullptr;
    }
    if (fCachedSimpleRenderPass) {
        fCachedSimpleRenderPass->unrefAndAbandon();
        fCachedSimpleRenderPass = nullptr;
    }
}

void GrVkRenderTarget::onRelease() {
    this->releaseInternalObjects();
    if (this->shouldFreeResources()) {
        this->releaseImage(this->getVkGpu());
    } else {
        this->abandonImage();
    }

    GrRenderTarget::onRelease();
}

void GrVkRenderTarget::onAbandon() {
    this->abandonInternalObjects();
    this->abandonImage();
    GrRenderTarget::onAbandon();
}


GrBackendObject GrVkRenderTarget::getRenderTargetHandle() const {
    // Currently just passing back the pointer to the main Image::Resource as the handle
    return (GrBackendObject)&fResource;
}

const GrVkImage::Resource* GrVkRenderTarget::stencilImageResource() const {
    const GrStencilAttachment* stencil = this->renderTargetPriv().getStencilAttachment();
    if (stencil) {
        const GrVkStencilAttachment* vkStencil = static_cast<const GrVkStencilAttachment*>(stencil);
        return vkStencil->imageResource();
    }

    return nullptr;
}

const GrVkImageView* GrVkRenderTarget::stencilAttachmentView() const {
    const GrStencilAttachment* stencil = this->renderTargetPriv().getStencilAttachment();
    if (stencil) {
        const GrVkStencilAttachment* vkStencil = static_cast<const GrVkStencilAttachment*>(stencil);
        return vkStencil->stencilView();
    }

    return nullptr;
}


GrVkGpu* GrVkRenderTarget::getVkGpu() const {
    SkASSERT(!this->wasDestroyed());
    return static_cast<GrVkGpu*>(this->getGpu());
}