Example #1
0
sk_sp<SkSurface> WindowContext::createSurface(
        sk_sp<GrRenderTarget> rt, int colorBits, bool offscreen, bool forceSRGB) {
    auto flags = (fSurfaceProps.flags() & ~SkSurfaceProps::kGammaCorrect_Flag) |
                 (GrPixelConfigIsSRGB(fPixelConfig) || forceSRGB ?
                  SkSurfaceProps::kGammaCorrect_Flag : 0);
    SkSurfaceProps props(flags, fSurfaceProps.pixelGeometry());

    if (!this->isGpuContext() || colorBits > 24 || offscreen ||
        kRGBA_F16_SkColorType == fDisplayParams.fColorType) {
        // If we're rendering to F16, we need an off-screen surface - the current render
        // target is most likely the wrong format.
        //
        // If we're rendering raster data or using a deep (10-bit or higher) surface, we probably
        // need an off-screen surface. 10-bit, in particular, has strange gamma behavior.
        SkImageInfo info = SkImageInfo::Make(
            fWidth, fHeight,
            fDisplayParams.fColorType,
            kPremul_SkAlphaType,
            forceSRGB ? SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named)
                      : fDisplayParams.fColorSpace
        );
        if (this->isGpuContext()) {
            return SkSurface::MakeRenderTarget(fContext, SkBudgeted::kNo, info,
                                               fDisplayParams.fMSAASampleCount, &props);
        } else {
            return SkSurface::MakeRaster(info, &props);
        }
    } else {
        return SkSurface::MakeRenderTargetDirect(rt.get(), &props);
    }
}
    bool onGetROPixels(SkBitmap* dst) const override {
        const auto desc = SkBitmapCacheDesc::Make(this->uniqueID(), this->width(), this->height());
        if (SkBitmapCache::Find(desc, dst)) {
            SkASSERT(dst->getGenerationID() == this->uniqueID());
            SkASSERT(dst->isImmutable());
            SkASSERT(dst->getPixels());
            return true;
        }

        SkPixmap pmap;
        SkImageInfo info = SkImageInfo::MakeN32(this->width(), this->height(),
                                                this->alphaType(), fColorSpace);
        auto rec = SkBitmapCache::Alloc(desc, info, &pmap);
        if (!rec) {
            return false;
        }
        sk_sp<SkColorSpace> colorSpace;
        if (GrPixelConfigIsSRGB(fTextureProxy->config())) {
            colorSpace = SkColorSpace::MakeSRGB();
        }
        sk_sp<GrSurfaceContext> sContext = fContext->contextPriv().makeWrappedSurfaceContext(
                fTextureProxy, std::move(colorSpace));
        if (!sContext) {
            return false;
        }

        if (!sContext->readPixels(info, pmap.writable_addr(), pmap.rowBytes(), 0, 0)) {
            return false;
        }

        SkBitmapCache::Add(std::move(rec), dst);
        fAddedRasterVersionToCache.store(true);
        return true;
    }
Example #3
0
sk_sp<GrTextureProxy> GrCopyBaseMipMapToTextureProxy(GrContext* ctx, GrTextureProxy* baseProxy) {
    SkASSERT(baseProxy);

    if (!ctx->caps()->isConfigCopyable(baseProxy->config())) {
        return nullptr;
    }

    GrProxyProvider* proxyProvider = ctx->contextPriv().proxyProvider();
    GrSurfaceDesc desc;
    desc.fFlags = kNone_GrSurfaceFlags;
    desc.fOrigin = baseProxy->origin();
    desc.fWidth = baseProxy->width();
    desc.fHeight = baseProxy->height();
    desc.fConfig = baseProxy->config();
    desc.fSampleCnt = 1;

    sk_sp<GrTextureProxy> proxy = proxyProvider->createMipMapProxy(desc, SkBudgeted::kYes);
    if (!proxy) {
        return nullptr;
    }

    // Copy the base layer to our proxy
    sk_sp<SkColorSpace> colorSpace;
    if (GrPixelConfigIsSRGB(proxy->config())) {
        colorSpace = SkColorSpace::MakeSRGB();
    }
    sk_sp<GrSurfaceContext> sContext =
            ctx->contextPriv().makeWrappedSurfaceContext(proxy, std::move(colorSpace));
    SkASSERT(sContext);
    SkAssertResult(sContext->copy(baseProxy));

    return proxy;
}
Example #4
0
void GrVkCaps::initConfigTable(const GrVkInterface* interface, VkPhysicalDevice physDev) {
    for (int i = 0; i < kGrPixelConfigCnt; ++i) {
        VkFormat format;
        if (GrPixelConfigToVkFormat(static_cast<GrPixelConfig>(i), &format)) {
            if (!GrPixelConfigIsSRGB(static_cast<GrPixelConfig>(i)) || fSRGBSupport) {
                fConfigTable[i].init(interface, physDev, format);
            }
        }
    }
}
Example #5
0
sk_sp<GrTextureProxy> GrTextureProducer::CopyOnGpu(GrContext* context,
                                                   sk_sp<GrTextureProxy> inputProxy,
                                                   const CopyParams& copyParams,
                                                   bool dstWillRequireMipMaps) {
    SkASSERT(context);

    const SkRect dstRect = SkRect::MakeIWH(copyParams.fWidth, copyParams.fHeight);
    GrMipMapped mipMapped = dstWillRequireMipMaps ? GrMipMapped::kYes : GrMipMapped::kNo;

    sk_sp<SkColorSpace> colorSpace;
    if (GrPixelConfigIsSRGB(inputProxy->config())) {
        colorSpace = SkColorSpace::MakeSRGB();
    }
    sk_sp<GrRenderTargetContext> copyRTC =
        context->contextPriv().makeDeferredRenderTargetContextWithFallback(
            SkBackingFit::kExact, dstRect.width(), dstRect.height(), inputProxy->config(),
            std::move(colorSpace), 1, mipMapped, inputProxy->origin());
    if (!copyRTC) {
        return nullptr;
    }

    GrPaint paint;
    paint.setGammaCorrect(true);

    SkRect localRect = SkRect::MakeWH(inputProxy->width(), inputProxy->height());

    bool needsDomain = false;
    if (copyParams.fFilter != GrSamplerState::Filter::kNearest) {
        bool resizing = localRect.width()  != dstRect.width() ||
                        localRect.height() != dstRect.height();
        needsDomain = resizing && !GrProxyProvider::IsFunctionallyExact(inputProxy.get());
    }

    if (needsDomain) {
        const SkRect domain = localRect.makeInset(0.5f, 0.5f);
        // This would cause us to read values from outside the subset. Surely, the caller knows
        // better!
        SkASSERT(copyParams.fFilter != GrSamplerState::Filter::kMipMap);
        paint.addColorFragmentProcessor(
            GrTextureDomainEffect::Make(std::move(inputProxy), SkMatrix::I(), domain,
                                        GrTextureDomain::kClamp_Mode, copyParams.fFilter));
    } else {
        GrSamplerState samplerState(GrSamplerState::WrapMode::kClamp, copyParams.fFilter);
        paint.addColorTextureProcessor(std::move(inputProxy), SkMatrix::I(), samplerState);
    }
    paint.setPorterDuffXPFactory(SkBlendMode::kSrc);

    copyRTC->fillRectToRect(GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(), dstRect,
                            localRect);
    return copyRTC->asTextureProxyRef();
}
Example #6
0
// In MDB mode the reffing of the 'getLastOpList' call's result allows in-progress
// GrOpLists to be picked up and added to by renderTargetContexts lower in the call
// stack. When this occurs with a closed GrOpList, a new one will be allocated
// when the renderTargetContext attempts to use it (via getOpList).
GrSurfaceContext::GrSurfaceContext(GrContext* context,
                                   GrDrawingManager* drawingMgr,
                                   GrPixelConfig config,
                                   sk_sp<SkColorSpace> colorSpace,
                                   GrAuditTrail* auditTrail,
                                   GrSingleOwner* singleOwner)
        : fContext(context)
        , fAuditTrail(auditTrail)
        , fColorSpaceInfo(std::move(colorSpace), config)
        , fDrawingManager(drawingMgr)
#ifdef SK_DEBUG
        , fSingleOwner(singleOwner)
#endif
{
    // We never should have a sRGB pixel config with a non-SRGB gamma color space.
    SkASSERT(!GrPixelConfigIsSRGB(config) ||
             (fColorSpaceInfo.colorSpace() && fColorSpaceInfo.colorSpace()->gammaCloseToSRGB()));
}
Example #7
0
sk_sp<GrTexture> GrYUVProvider::refAsTexture(GrContext* ctx,
        const GrSurfaceDesc& desc,
        bool useCache) {
    SkYUVPlanesCache::Info yuvInfo;
    void* planes[3];
    YUVScoper scoper;
    if (!scoper.init(this, &yuvInfo, planes, useCache)) {
        return nullptr;
    }

    GrSurfaceDesc yuvDesc;
    yuvDesc.fConfig = kAlpha_8_GrPixelConfig;
    SkAutoTUnref<GrTexture> yuvTextures[3];
    for (int i = 0; i < 3; i++) {
        yuvDesc.fWidth  = yuvInfo.fSizeInfo.fSizes[i].fWidth;
        yuvDesc.fHeight = yuvInfo.fSizeInfo.fSizes[i].fHeight;
        // TODO: why do we need this check?
        bool needsExactTexture =
            (yuvDesc.fWidth  != yuvInfo.fSizeInfo.fSizes[SkYUVSizeInfo::kY].fWidth) ||
            (yuvDesc.fHeight != yuvInfo.fSizeInfo.fSizes[SkYUVSizeInfo::kY].fHeight);
        if (needsExactTexture) {
            yuvTextures[i].reset(ctx->textureProvider()->createTexture(yuvDesc, SkBudgeted::kYes));
        } else {
            yuvTextures[i].reset(ctx->textureProvider()->createApproxTexture(yuvDesc));
        }
        if (!yuvTextures[i] ||
                !yuvTextures[i]->writePixels(0, 0, yuvDesc.fWidth, yuvDesc.fHeight, yuvDesc.fConfig,
                                             planes[i], yuvInfo.fSizeInfo.fWidthBytes[i])) {
            return nullptr;
        }
    }

    sk_sp<GrDrawContext> drawContext(ctx->newDrawContext(SkBackingFit::kExact,
                                     desc.fWidth, desc.fHeight,
                                     desc.fConfig, desc.fSampleCnt));
    if (!drawContext) {
        return nullptr;
    }

    GrPaint paint;
    sk_sp<GrFragmentProcessor> yuvToRgbProcessor(
        GrYUVEffect::MakeYUVToRGB(yuvTextures[0], yuvTextures[1], yuvTextures[2],
                                  yuvInfo.fSizeInfo.fSizes, yuvInfo.fColorSpace, false));
    paint.addColorFragmentProcessor(std::move(yuvToRgbProcessor));

    // If we're decoding an sRGB image, the result of our linear math on the YUV planes is already
    // in sRGB. (The encoding is just math on bytes, with no concept of color spaces.) So, we need
    // to output the results of that math directly to the buffer that we will then consider sRGB.
    // If we have sRGB write control, we can just tell the HW not to do the Linear -> sRGB step.
    // Otherwise, we do our shader math to go from YUV -> sRGB, manually convert sRGB -> Linear,
    // then let the HW convert Linear -> sRGB.
    if (GrPixelConfigIsSRGB(desc.fConfig)) {
        if (ctx->caps()->srgbWriteControl()) {
            paint.setDisableOutputConversionToSRGB(true);
        } else {
            paint.addColorFragmentProcessor(GrGammaEffect::Make(2.2f));
        }
    }

    paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode);
    const SkRect r = SkRect::MakeIWH(yuvInfo.fSizeInfo.fSizes[SkYUVSizeInfo::kY].fWidth,
                                     yuvInfo.fSizeInfo.fSizes[SkYUVSizeInfo::kY].fHeight);

    drawContext->drawRect(GrNoClip(), paint, SkMatrix::I(), r);

    return drawContext->asTexture();
}
sk_sp<GrColorSpaceXform> GrColorSpaceXform::Make(const SkColorSpace* src,
                                                 GrPixelConfig srcConfig,
                                                 const SkColorSpace* dst) {
    if (!dst) {
        // No transformation is performed in legacy mode
        return nullptr;
    }

    // Treat null sources as sRGB
    if (!src) {
        if (GrPixelConfigIsFloatingPoint(srcConfig)) {
            src = SkColorSpace::MakeSRGBLinear().get();
        } else {
            src = SkColorSpace::MakeSRGB().get();
        }
    }

    uint32_t flags = 0;
    SkColorSpaceTransferFn srcTransferFn;

    // kUnknown_GrPixelConfig is a sentinel that means we don't care about transfer functions,
    // just the gamut xform.
    if (kUnknown_GrPixelConfig != srcConfig) {
        // Determine if src transfer function is needed, based on src config and color space
        if (GrPixelConfigIsSRGB(srcConfig)) {
            // Source texture is sRGB, will be converted to linear when we sample
            if (src->gammaCloseToSRGB()) {
                // Hardware linearize does the right thing
            } else if (src->gammaIsLinear()) {
                // Oops, need to undo the (extra) linearize
                flags |= kApplyInverseSRGB_Flag;
            } else if (src->isNumericalTransferFn(&srcTransferFn)) {
                // Need to undo the (extra) linearize, then apply the correct transfer function
                flags |= (kApplyInverseSRGB_Flag | kApplyTransferFn_Flag);
            } else {
                // We don't (yet) support more complex transfer functions
                return nullptr;
            }
        } else {
            // Source texture is some non-sRGB format, we consider it linearly encoded
            if (src->gammaIsLinear()) {
                // Linear sampling does the right thing
            } else if (src->isNumericalTransferFn(&srcTransferFn)) {
                // Need to manually apply some transfer function (including sRGB)
                flags |= kApplyTransferFn_Flag;
            } else {
                // We don't (yet) support more complex transfer functions
                return nullptr;
            }
        }
    }
    if (src == dst && (0 == flags)) {
        // Quick equality check - no conversion (or transfer function) needed in this case
        return nullptr;
    }

    const SkMatrix44* toXYZD50   = src->toXYZD50();
    const SkMatrix44* fromXYZD50 = dst->fromXYZD50();
    if (!toXYZD50 || !fromXYZD50) {
        // Unsupported colour spaces -- cannot specify gamut as a matrix
        return nullptr;
    }

    // Determine if a gamut xform is needed
    uint32_t srcHash = src->toXYZD50Hash();
    uint32_t dstHash = dst->toXYZD50Hash();
    if (srcHash != dstHash) {
        flags |= kApplyGamutXform_Flag;
    } else {
        SkASSERT(*toXYZD50 == *dst->toXYZD50() && "Hash collision");
    }

    if (0 == flags) {
        // Identical gamut and no transfer function - no conversion needed in this case
        return nullptr;
    }

    auto makeXform = [srcTransferFn, fromXYZD50, toXYZD50, flags]() {
        SkMatrix44 srcToDst(SkMatrix44::kUninitialized_Constructor);
        if (SkToBool(flags & kApplyGamutXform_Flag)) {
            srcToDst.setConcat(*fromXYZD50, *toXYZD50);
        } else {
            srcToDst.setIdentity();
        }
        return sk_make_sp<GrColorSpaceXform>(srcTransferFn, srcToDst, flags);
    };

    // For now, we only cache pure gamut xforms (no transfer functions)
    // TODO: Fold a hash of the transfer function into the cache key
    if ((kApplyGamutXform_Flag == flags) && gColorSpaceXformCacheSpinlock.tryAcquire()) {
        static GrColorSpaceXformCache* gCache;
        if (nullptr == gCache) {
            gCache = new GrColorSpaceXformCache();
        }

        uint64_t key = static_cast<uint64_t>(srcHash) << 32 | static_cast<uint64_t>(dstHash);
        sk_sp<GrColorSpaceXform> xform = gCache->findOrAdd(key, makeXform);
        gColorSpaceXformCacheSpinlock.release();
        return xform;
    } else {
        // If our xform has non-gamut components, or we can't get the spin lock, just build it
        return makeXform();
    }
}
Example #9
0
bool VulkanWindowContext::createSwapchain(uint32_t width, uint32_t height,
                                          const DisplayParams& params) {
    // check for capabilities
    VkSurfaceCapabilitiesKHR caps;
    VkResult res = fGetPhysicalDeviceSurfaceCapabilitiesKHR(fBackendContext->fPhysicalDevice,
                                                            fSurface, &caps);
    if (VK_SUCCESS != res) {
        return false;
    }

    uint32_t surfaceFormatCount;
    res = fGetPhysicalDeviceSurfaceFormatsKHR(fBackendContext->fPhysicalDevice, fSurface,
                                              &surfaceFormatCount, nullptr);
    if (VK_SUCCESS != res) {
        return false;
    }

    SkAutoMalloc surfaceFormatAlloc(surfaceFormatCount * sizeof(VkSurfaceFormatKHR));
    VkSurfaceFormatKHR* surfaceFormats = (VkSurfaceFormatKHR*)surfaceFormatAlloc.get();
    res = fGetPhysicalDeviceSurfaceFormatsKHR(fBackendContext->fPhysicalDevice, fSurface,
                                              &surfaceFormatCount, surfaceFormats);
    if (VK_SUCCESS != res) {
        return false;
    }

    uint32_t presentModeCount;
    res = fGetPhysicalDeviceSurfacePresentModesKHR(fBackendContext->fPhysicalDevice, fSurface,
                                                   &presentModeCount, nullptr);
    if (VK_SUCCESS != res) {
        return false;
    }

    SkAutoMalloc presentModeAlloc(presentModeCount * sizeof(VkPresentModeKHR));
    VkPresentModeKHR* presentModes = (VkPresentModeKHR*)presentModeAlloc.get();
    res = fGetPhysicalDeviceSurfacePresentModesKHR(fBackendContext->fPhysicalDevice, fSurface,
                                                   &presentModeCount, presentModes);
    if (VK_SUCCESS != res) {
        return false;
    }

    VkExtent2D extent = caps.currentExtent;
    // use the hints
    if (extent.width == (uint32_t)-1) {
        extent.width = width;
        extent.height = height;
    }

    // clamp width; to protect us from broken hints
    if (extent.width < caps.minImageExtent.width) {
        extent.width = caps.minImageExtent.width;
    } else if (extent.width > caps.maxImageExtent.width) {
        extent.width = caps.maxImageExtent.width;
    }
    // clamp height
    if (extent.height < caps.minImageExtent.height) {
        extent.height = caps.minImageExtent.height;
    } else if (extent.height > caps.maxImageExtent.height) {
        extent.height = caps.maxImageExtent.height;
    }

    fWidth = (int)extent.width;
    fHeight = (int)extent.height;

    uint32_t imageCount = caps.minImageCount + 2;
    if (caps.maxImageCount > 0 && imageCount > caps.maxImageCount) {
        // Application must settle for fewer images than desired:
        imageCount = caps.maxImageCount;
    }

    VkImageUsageFlags usageFlags = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
                                   VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
                                   VK_IMAGE_USAGE_TRANSFER_DST_BIT;
    SkASSERT((caps.supportedUsageFlags & usageFlags) == usageFlags);
    SkASSERT(caps.supportedTransforms & caps.currentTransform);
    SkASSERT(caps.supportedCompositeAlpha & (VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR |
                                             VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR));
    VkCompositeAlphaFlagBitsKHR composite_alpha =
        (caps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR) ?
                                        VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR :
                                        VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;

    // Pick our surface format. For now, just make sure it matches our sRGB request:
    VkFormat surfaceFormat = VK_FORMAT_UNDEFINED;
    VkColorSpaceKHR colorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR;
    bool wantSRGB = kSRGB_SkColorProfileType == params.fProfileType;
    for (uint32_t i = 0; i < surfaceFormatCount; ++i) {
        GrPixelConfig config;
        if (GrVkFormatToPixelConfig(surfaceFormats[i].format, &config) &&
            GrPixelConfigIsSRGB(config) == wantSRGB) {
            surfaceFormat = surfaceFormats[i].format;
            colorSpace = surfaceFormats[i].colorSpace;
            break;
        }
    }
    fDisplayParams = params;

    if (VK_FORMAT_UNDEFINED == surfaceFormat) {
        return false;
    }

    // If mailbox mode is available, use it, as it is the lowest-latency non-
    // tearing mode. If not, fall back to FIFO which is always available.
    VkPresentModeKHR mode = VK_PRESENT_MODE_FIFO_KHR;
    for (uint32_t i = 0; i < presentModeCount; ++i) {
        // use mailbox
        if (VK_PRESENT_MODE_MAILBOX_KHR == presentModes[i]) {
            mode = presentModes[i];
            break;
        }
    }

    VkSwapchainCreateInfoKHR swapchainCreateInfo;
    memset(&swapchainCreateInfo, 0, sizeof(VkSwapchainCreateInfoKHR));
    swapchainCreateInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
    swapchainCreateInfo.surface = fSurface;
    swapchainCreateInfo.minImageCount = imageCount;
    swapchainCreateInfo.imageFormat = surfaceFormat;
    swapchainCreateInfo.imageColorSpace = colorSpace;
    swapchainCreateInfo.imageExtent = extent;
    swapchainCreateInfo.imageArrayLayers = 1;
    swapchainCreateInfo.imageUsage = usageFlags;

    uint32_t queueFamilies[] = { fBackendContext->fGraphicsQueueIndex, fPresentQueueIndex };
    if (fBackendContext->fGraphicsQueueIndex != fPresentQueueIndex) {
        swapchainCreateInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
        swapchainCreateInfo.queueFamilyIndexCount = 2;
        swapchainCreateInfo.pQueueFamilyIndices = queueFamilies;
    } else {
        swapchainCreateInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
        swapchainCreateInfo.queueFamilyIndexCount = 0;
        swapchainCreateInfo.pQueueFamilyIndices = nullptr;
    }

    swapchainCreateInfo.preTransform = caps.currentTransform;;
    swapchainCreateInfo.compositeAlpha = composite_alpha;
    swapchainCreateInfo.presentMode = mode;
    swapchainCreateInfo.clipped = true;
    swapchainCreateInfo.oldSwapchain = fSwapchain;

    res = fCreateSwapchainKHR(fBackendContext->fDevice, &swapchainCreateInfo, nullptr, &fSwapchain);
    if (VK_SUCCESS != res) {
        return false;
    }

    // destroy the old swapchain
    if (swapchainCreateInfo.oldSwapchain != VK_NULL_HANDLE) {
        GR_VK_CALL(fBackendContext->fInterface, DeviceWaitIdle(fBackendContext->fDevice));

        this->destroyBuffers();

        fDestroySwapchainKHR(fBackendContext->fDevice, swapchainCreateInfo.oldSwapchain, nullptr);
    }

    this->createBuffers(swapchainCreateInfo.imageFormat);

    return true;
}
void VulkanWindowContext::createBuffers(VkFormat format) {
    GrVkFormatToPixelConfig(format, &fPixelConfig);

    fGetSwapchainImagesKHR(fBackendContext->fDevice, fSwapchain, &fImageCount, nullptr);
    SkASSERT(fImageCount);
    fImages = new VkImage[fImageCount];
    fGetSwapchainImagesKHR(fBackendContext->fDevice, fSwapchain, &fImageCount, fImages);

    // set up initial image layouts and create surfaces
    fImageLayouts = new VkImageLayout[fImageCount];
    fSurfaces = new sk_sp<SkSurface>[fImageCount];
    for (uint32_t i = 0; i < fImageCount; ++i) {
        fImageLayouts[i] = VK_IMAGE_LAYOUT_UNDEFINED;

        GrBackendRenderTargetDesc desc;
        GrVkImageInfo info;
        info.fImage = fImages[i];
        info.fAlloc = VK_NULL_HANDLE;
        info.fImageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
        info.fImageTiling = VK_IMAGE_TILING_OPTIMAL;
        info.fFormat = format;
        info.fLevelCount = 1;
        desc.fWidth = fWidth;
        desc.fHeight = fHeight;
        desc.fConfig = fPixelConfig;
        desc.fOrigin = kTopLeft_GrSurfaceOrigin;
        desc.fSampleCnt = 0;
        desc.fStencilBits = 0;
        desc.fRenderTargetHandle = (GrBackendObject) &info;
        SkSurfaceProps props(GrPixelConfigIsSRGB(fPixelConfig)
                             ? SkSurfaceProps::kGammaCorrect_Flag : 0,
                             kUnknown_SkPixelGeometry);
        fSurfaces[i] = SkSurface::MakeFromBackendRenderTarget(fContext, desc, &props);
    }

    // create the command pool for the command buffers
    if (VK_NULL_HANDLE == fCommandPool) {
        VkCommandPoolCreateInfo commandPoolInfo;
        memset(&commandPoolInfo, 0, sizeof(VkCommandPoolCreateInfo));
        commandPoolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
        // this needs to be on the render queue
        commandPoolInfo.queueFamilyIndex = fBackendContext->fGraphicsQueueIndex;
        commandPoolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
        GR_VK_CALL_ERRCHECK(fBackendContext->fInterface,
                            CreateCommandPool(fBackendContext->fDevice, &commandPoolInfo,
                                              nullptr, &fCommandPool));
    }

    // set up the backbuffers
    VkSemaphoreCreateInfo semaphoreInfo;
    memset(&semaphoreInfo, 0, sizeof(VkSemaphoreCreateInfo));
    semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
    semaphoreInfo.pNext = nullptr;
    semaphoreInfo.flags = 0;
    VkCommandBufferAllocateInfo commandBuffersInfo;
    memset(&commandBuffersInfo, 0, sizeof(VkCommandBufferAllocateInfo));
    commandBuffersInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
    commandBuffersInfo.pNext = nullptr;
    commandBuffersInfo.commandPool = fCommandPool;
    commandBuffersInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
    commandBuffersInfo.commandBufferCount = 2;
    VkFenceCreateInfo fenceInfo;
    memset(&fenceInfo, 0, sizeof(VkFenceCreateInfo));
    fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
    fenceInfo.pNext = nullptr;
    fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;

    // we create one additional backbuffer structure here, because we want to 
    // give the command buffers they contain a chance to finish before we cycle back
    fBackbuffers = new BackbufferInfo[fImageCount + 1];
    for (uint32_t i = 0; i < fImageCount + 1; ++i) {
        fBackbuffers[i].fImageIndex = -1;
        GR_VK_CALL_ERRCHECK(fBackendContext->fInterface,
                            CreateSemaphore(fBackendContext->fDevice, &semaphoreInfo,
                                            nullptr, &fBackbuffers[i].fAcquireSemaphore));
        GR_VK_CALL_ERRCHECK(fBackendContext->fInterface,
                            CreateSemaphore(fBackendContext->fDevice, &semaphoreInfo,
                                            nullptr, &fBackbuffers[i].fRenderSemaphore));
        GR_VK_CALL_ERRCHECK(fBackendContext->fInterface,
                            AllocateCommandBuffers(fBackendContext->fDevice, &commandBuffersInfo,
                                                   fBackbuffers[i].fTransitionCmdBuffers));
        GR_VK_CALL_ERRCHECK(fBackendContext->fInterface,
                            CreateFence(fBackendContext->fDevice, &fenceInfo, nullptr,
                                        &fBackbuffers[i].fUsageFences[0]));
        GR_VK_CALL_ERRCHECK(fBackendContext->fInterface,
                            CreateFence(fBackendContext->fDevice, &fenceInfo, nullptr,
                                        &fBackbuffers[i].fUsageFences[1]));
    }
    fCurrentBackbufferIndex = fImageCount;
}
sk_sp<GrTextureProxy> GrYUVProvider::refAsTextureProxy(GrContext* ctx, const GrSurfaceDesc& desc,
                                                       const SkColorSpace* srcColorSpace,
                                                       const SkColorSpace* dstColorSpace) {
    SkYUVPlanesCache::Info yuvInfo;
    void* planes[3];

    sk_sp<SkCachedData>  dataStorage = init_provider(this, &yuvInfo, planes);
    if (!dataStorage) {
        return nullptr;
    }

    sk_sp<GrTextureProxy> yuvTextureProxies[3];
    for (int i = 0; i < 3; i++) {
        int componentWidth  = yuvInfo.fSizeInfo.fSizes[i].fWidth;
        int componentHeight = yuvInfo.fSizeInfo.fSizes[i].fHeight;
        // If the sizes of the components are not all the same we choose to create exact-match
        // textures for the smaller onces rather than add a texture domain to the draw.
        // TODO: revisit this decision to imporve texture reuse?
        SkBackingFit fit =
                (componentWidth  != yuvInfo.fSizeInfo.fSizes[SkYUVSizeInfo::kY].fWidth) ||
                (componentHeight != yuvInfo.fSizeInfo.fSizes[SkYUVSizeInfo::kY].fHeight)
                    ? SkBackingFit::kExact : SkBackingFit::kApprox;

        SkImageInfo imageInfo = SkImageInfo::MakeA8(componentWidth, componentHeight);
        SkPixmap pixmap(imageInfo, planes[i], yuvInfo.fSizeInfo.fWidthBytes[i]);
        SkCachedData* dataStoragePtr = dataStorage.get();
        // We grab a ref to cached yuv data. When the SkImage we create below goes away it will call
        // the YUVGen_DataReleaseProc which will release this ref.
        // DDL TODO: Currently we end up creating a lazy proxy that will hold onto a ref to the
        // SkImage in its lambda. This means that we'll keep the ref on the YUV data around for the
        // life time of the proxy and not just upload. For non-DDL draws we should look into
        // releasing this SkImage after uploads (by deleting the lambda after instantiation).
        dataStoragePtr->ref();
        sk_sp<SkImage> yuvImage = SkImage::MakeFromRaster(pixmap, YUVGen_DataReleaseProc,
                                                          dataStoragePtr);

        auto proxyProvider = ctx->contextPriv().proxyProvider();
        yuvTextureProxies[i] = proxyProvider->createTextureProxy(yuvImage, kNone_GrSurfaceFlags,
                                                                 kTopLeft_GrSurfaceOrigin,
                                                                 1, SkBudgeted::kYes, fit);
    }

    // We never want to perform color-space conversion during the decode. However, if the proxy
    // config is sRGB then we must use a sRGB color space.
    sk_sp<SkColorSpace> colorSpace;
    if (GrPixelConfigIsSRGB(desc.fConfig)) {
        colorSpace = SkColorSpace::MakeSRGB();
    }
    // TODO: investigate preallocating mip maps here
    sk_sp<GrRenderTargetContext> renderTargetContext(ctx->makeDeferredRenderTargetContext(
            SkBackingFit::kExact, desc.fWidth, desc.fHeight, desc.fConfig, std::move(colorSpace),
            desc.fSampleCnt, GrMipMapped::kNo, kTopLeft_GrSurfaceOrigin));
    if (!renderTargetContext) {
        return nullptr;
    }

    GrPaint paint;
    auto yuvToRgbProcessor =
            GrYUVtoRGBEffect::Make(std::move(yuvTextureProxies[0]),
                                   std::move(yuvTextureProxies[1]),
                                   std::move(yuvTextureProxies[2]),
                                   yuvInfo.fSizeInfo.fSizes, yuvInfo.fColorSpace, false);
    paint.addColorFragmentProcessor(std::move(yuvToRgbProcessor));

    // If we're decoding an sRGB image, the result of our linear math on the YUV planes is already
    // in sRGB. (The encoding is just math on bytes, with no concept of color spaces.) So, we need
    // to output the results of that math directly to the buffer that we will then consider sRGB.
    // If we have sRGB write control, we can just tell the HW not to do the Linear -> sRGB step.
    // Otherwise, we do our shader math to go from YUV -> sRGB, manually convert sRGB -> Linear,
    // then let the HW convert Linear -> sRGB.
    if (GrPixelConfigIsSRGB(desc.fConfig)) {
        if (ctx->caps()->srgbWriteControl()) {
            paint.setDisableOutputConversionToSRGB(true);
        } else {
            paint.addColorFragmentProcessor(GrSRGBEffect::Make(GrSRGBEffect::Mode::kSRGBToLinear,
                                                               GrSRGBEffect::Alpha::kOpaque));
        }
    }

    // If the caller expects the pixels in a different color space than the one from the image,
    // apply a color conversion to do this.
    std::unique_ptr<GrFragmentProcessor> colorConversionProcessor =
            GrNonlinearColorSpaceXformEffect::Make(srcColorSpace, dstColorSpace);
    if (colorConversionProcessor) {
        paint.addColorFragmentProcessor(std::move(colorConversionProcessor));
    }

    paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
    const SkRect r = SkRect::MakeIWH(yuvInfo.fSizeInfo.fSizes[SkYUVSizeInfo::kY].fWidth,
                                     yuvInfo.fSizeInfo.fSizes[SkYUVSizeInfo::kY].fHeight);

    renderTargetContext->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(), r);

    return renderTargetContext->asTextureProxyRef();
}
Example #12
0
bool GrGpu::getWritePixelsInfo(GrSurface* dstSurface, GrSurfaceOrigin dstOrigin, int width,
                               int height, GrColorType srcColorType,
                               GrSRGBConversion srgbConversion, DrawPreference* drawPreference,
                               WritePixelTempDrawInfo* tempDrawInfo) {
    SkASSERT(drawPreference);
    SkASSERT(tempDrawInfo);
    SkASSERT(dstSurface);
    SkASSERT(kGpuPrefersDraw_DrawPreference != *drawPreference);

    GrPixelConfig tempSurfaceConfig = kUnknown_GrPixelConfig;
    // GrGpu::writePixels doesn't do any sRGB conversions, so we must draw if there is one.
    switch (srgbConversion) {
        case GrSRGBConversion::kNone:
            // We support writing just A to a RGBA. In that case there is no sRGB version of the
            // src format but we still want to succeed.
            if (GrColorTypeIsAlphaOnly(srcColorType)) {
                tempSurfaceConfig = GrColorTypeToPixelConfig(srcColorType, GrSRGBEncoded::kNo);
            } else {
                tempSurfaceConfig = GrColorTypeToPixelConfig(
                        srcColorType, GrPixelConfigIsSRGBEncoded(dstSurface->config()));
            }
            break;
        case GrSRGBConversion::kLinearToSRGB:
            SkASSERT(this->caps()->srgbSupport());
            // This assert goes away when we start referring to CPU data using color type.
            tempSurfaceConfig = GrColorTypeToPixelConfig(srcColorType, GrSRGBEncoded::kNo);
            // We don't currently support storing sRGB encoded data in a surface unless it is
            // an SRGB-encoded config. That is likely to change when we need to store sRGB encoded
            // data in 101010102 and F16 textures. We'll have to provoke the caller to do the
            // conversion in a shader.
            if (!GrPixelConfigIsSRGB(dstSurface->config())) {
                return false;
            }
            ElevateDrawPreference(drawPreference, kRequireDraw_DrawPreference);
            break;
        case GrSRGBConversion::kSRGBToLinear:
            SkASSERT(this->caps()->srgbSupport());
            tempSurfaceConfig = GrColorTypeToPixelConfig(srcColorType, GrSRGBEncoded::kYes);
            // Currently we don't expect to make a SRGB encoded surface and then succeed at
            // treating it as though it were linear and then convert to sRGB.
            if (GrSRGBEncoded::kYes == GrPixelConfigIsSRGBEncoded(dstSurface->config())) {
                return false;
            }
            ElevateDrawPreference(drawPreference, kRequireDraw_DrawPreference);
            break;
    }
    if (kUnknown_GrPixelConfig == tempSurfaceConfig) {
        return false;
    }

    // Default values for intermediate draws. The intermediate texture config matches the dst's
    // config, is approx sized to the write rect, no swizzling or sppofing of the src config.
    tempDrawInfo->fTempSurfaceDesc.fFlags = kNone_GrSurfaceFlags;
    tempDrawInfo->fTempSurfaceDesc.fConfig = tempSurfaceConfig;
    tempDrawInfo->fTempSurfaceDesc.fWidth = width;
    tempDrawInfo->fTempSurfaceDesc.fHeight = height;
    tempDrawInfo->fTempSurfaceDesc.fSampleCnt = 1;
    tempDrawInfo->fSwizzle = GrSwizzle::RGBA();
    tempDrawInfo->fWriteColorType = srcColorType;

    if (!this->onGetWritePixelsInfo(dstSurface, dstOrigin, width, height, srcColorType,
                                    drawPreference, tempDrawInfo)) {
        return false;
    }

    // Check to see if we're going to request that the caller draw when drawing is not possible.
    if (!dstSurface->asRenderTarget() ||
        !this->caps()->isConfigTexturable(tempDrawInfo->fTempSurfaceDesc.fConfig)) {
        // If we don't have a fallback to a straight upload then fail.
        if (kRequireDraw_DrawPreference == *drawPreference /*TODO ||
            !this->caps()->isConfigTexturable(srcConfig)*/) {
            return false;
        }
        *drawPreference = kNoDraw_DrawPreference;
    }
    return true;
}
Example #13
0
bool GrGpu::getReadPixelsInfo(GrSurface* srcSurface, GrSurfaceOrigin srcOrigin, int width,
                              int height, size_t rowBytes, GrColorType dstColorType,
                              GrSRGBConversion srgbConversion, DrawPreference* drawPreference,
                              ReadPixelTempDrawInfo* tempDrawInfo) {
    SkASSERT(drawPreference);
    SkASSERT(tempDrawInfo);
    SkASSERT(srcSurface);
    SkASSERT(kGpuPrefersDraw_DrawPreference != *drawPreference);

    // We currently do not support reading into the packed formats 565 or 4444 as they are not
    // required to have read back support on all devices and backends.
    if (GrColorType::kRGB_565 == dstColorType || GrColorType::kABGR_4444 == dstColorType) {
        return false;
    }

    GrPixelConfig tempSurfaceConfig = kUnknown_GrPixelConfig;
    // GrGpu::readPixels doesn't do any sRGB conversions, so we must draw if there is one.
    switch (srgbConversion) {
        case GrSRGBConversion::kNone:
            // We support reading from RGBA to just A. In that case there is no sRGB version of the
            // dst format but we still want to succeed.
            if (GrColorTypeIsAlphaOnly(dstColorType)) {
                tempSurfaceConfig = GrColorTypeToPixelConfig(dstColorType, GrSRGBEncoded::kNo);
            } else {
                tempSurfaceConfig = GrColorTypeToPixelConfig(
                        dstColorType, GrPixelConfigIsSRGBEncoded(srcSurface->config()));
            }
            break;
        case GrSRGBConversion::kLinearToSRGB:
            SkASSERT(this->caps()->srgbSupport());
            tempSurfaceConfig = GrColorTypeToPixelConfig(dstColorType, GrSRGBEncoded::kYes);
            // Currently we don't expect to make a SRGB encoded surface and then read data from it
            // such that we treat it as though it were linear and is then converted to sRGB.
            if (GrPixelConfigIsSRGB(srcSurface->config())) {
                return false;
            }
            ElevateDrawPreference(drawPreference, kRequireDraw_DrawPreference);
            break;
        case GrSRGBConversion::kSRGBToLinear:
            SkASSERT(this->caps()->srgbSupport());
            tempSurfaceConfig = GrColorTypeToPixelConfig(dstColorType, GrSRGBEncoded::kNo);
            // We don't currently support reading sRGB encoded data into linear from a surface
            // unless it is an sRGB-encoded config. That is likely to change when we need to store
            // sRGB encoded data in 101010102 and F16 textures. We'll have to provoke the caller to
            // do the conversion in a shader.
            if (GrSRGBEncoded::kNo == GrPixelConfigIsSRGBEncoded(srcSurface->config())) {
                return false;
            }
            ElevateDrawPreference(drawPreference, kRequireDraw_DrawPreference);
            break;
    }
    if (kUnknown_GrPixelConfig == tempSurfaceConfig) {
        return false;
    }

    // Default values for intermediate draws. The intermediate texture config matches the dst's
    // config, is approx sized to the read rect, no swizzling or spoofing of the dst config.
    tempDrawInfo->fTempSurfaceDesc.fFlags = kRenderTarget_GrSurfaceFlag;
    tempDrawInfo->fTempSurfaceDesc.fWidth = width;
    tempDrawInfo->fTempSurfaceDesc.fHeight = height;
    tempDrawInfo->fTempSurfaceDesc.fSampleCnt = 1;
    tempDrawInfo->fTempSurfaceDesc.fConfig = tempSurfaceConfig;
    tempDrawInfo->fTempSurfaceFit = SkBackingFit::kApprox;
    tempDrawInfo->fSwizzle = GrSwizzle::RGBA();
    tempDrawInfo->fReadColorType = dstColorType;

    if (!this->onGetReadPixelsInfo(srcSurface, srcOrigin, width, height, rowBytes, dstColorType,
                                   drawPreference, tempDrawInfo)) {
        return false;
    }

    // Check to see if we're going to request that the caller draw when drawing is not possible.
    if (!srcSurface->asTexture() ||
        !this->caps()->isConfigRenderable(tempDrawInfo->fTempSurfaceDesc.fConfig)) {
        // If we don't have a fallback to a straight read then fail.
        if (kRequireDraw_DrawPreference == *drawPreference) {
            return false;
        }
        *drawPreference = kNoDraw_DrawPreference;
    }

    return true;
}