/* * Copyright 2011 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include "src/gpu/ganesh/GrAttachment.h" #include "include/gpu/GpuTypes.h" #include "include/private/base/SkAssert.h" #include "include/private/base/SkTo.h" #include "src/gpu/DataUtils.h" #include "src/gpu/ResourceKey.h" #include "src/gpu/ganesh/GrBackendUtils.h" #include "src/gpu/ganesh/GrCaps.h" #include "src/gpu/ganesh/GrGpu.h" enum class SkTextureCompressionType; size_t GrAttachment::onGpuMemorySize() const { // The GrTexture[RenderTarget] is built up by a bunch of attachments each of which are their // own GrGpuResource. Ideally the GrRenderTarget would not be a GrGpuResource and the GrTexture // would just merge with the new GrSurface/Attachment world. Then we could just depend on each // attachment to give its own size since we don't have GrGpuResources owning other // GrGpuResources. Until we get to that point we need to live in some hybrid world. We will let // the msaa and stencil attachments track their own size because they do get cached separately. // For all GrTexture* based things we will continue to to use the GrTexture* to report size and // the owned attachments will have no size and be uncached. if (!(fSupportedUsages & UsageFlags::kTexture) && fMemoryless == GrMemoryless::kNo) { GrBackendFormat format = this->backendFormat(); SkTextureCompressionType compression = GrBackendFormatToCompressionType(format); uint64_t size = skgpu::NumCompressedBlocks(compression, this->dimensions()); size *= GrBackendFormatBytesPerBlock(this->backendFormat()); size *= this->numSamples(); return size; } return 0; } static void build_key(skgpu::ResourceKey::Builder* builder, const GrCaps& caps, const GrBackendFormat& format, SkISize dimensions, GrAttachment::UsageFlags requiredUsage, int sampleCnt, skgpu::Mipmapped mipmapped, GrProtected isProtected, GrMemoryless memoryless) { SkASSERT(!dimensions.isEmpty()); SkASSERT(static_cast(isProtected) <= 1); SkASSERT(static_cast(memoryless) <= 1); SkASSERT(static_cast(requiredUsage) < (1u << 8)); SkASSERT(static_cast(sampleCnt) < (1u << (32 - 10))); uint64_t formatKey = caps.computeFormatKey(format); (*builder)[0] = dimensions.width(); (*builder)[1] = dimensions.height(); (*builder)[2] = formatKey & 0xFFFFFFFF; (*builder)[3] = (formatKey >> 32) & 0xFFFFFFFF; (*builder)[4] = (static_cast(isProtected) << 0) | (static_cast(memoryless) << 1) | (static_cast(requiredUsage) << 2) | (static_cast(sampleCnt) << 10); } void GrAttachment::ComputeSharedAttachmentUniqueKey(const GrCaps& caps, const GrBackendFormat& format, SkISize dimensions, UsageFlags requiredUsage, int sampleCnt, skgpu::Mipmapped mipmapped, GrProtected isProtected, GrMemoryless memoryless, skgpu::UniqueKey* key) { static const skgpu::UniqueKey::Domain kDomain = skgpu::UniqueKey::GenerateDomain(); skgpu::UniqueKey::Builder builder(key, kDomain, 5); build_key(&builder, caps, format, dimensions, requiredUsage, sampleCnt, mipmapped, isProtected, memoryless); } void GrAttachment::ComputeScratchKey(const GrCaps& caps, const GrBackendFormat& format, SkISize dimensions, UsageFlags requiredUsage, int sampleCnt, skgpu::Mipmapped mipmapped, GrProtected isProtected, GrMemoryless memoryless, skgpu::ScratchKey* key) { static const skgpu::ScratchKey::ResourceType kType = skgpu::ScratchKey::GenerateResourceType(); skgpu::ScratchKey::Builder builder(key, kType, 5); build_key(&builder, caps, format, dimensions, requiredUsage, sampleCnt, mipmapped, isProtected, memoryless); } void GrAttachment::computeScratchKey(skgpu::ScratchKey* key) const { // We do don't cache GrAttachments as scratch resources when used for stencils or textures. For // stencils we share/cache them with unique keys so that they can be shared. Textures are in a // weird place on the Vulkan backend. Currently, GrVkTexture contains a GrAttachment (GrVkImage) // that actually holds the VkImage. The GrVkTexture is cached as a scratch resource and is // responsible for tracking the gpuMemorySize. Thus we set the size of the texture GrVkImage, // above in onGpuMemorySize, to be zero. Therefore, we can't have the GrVkImage getting cached // separately on its own in the GrResourceCache or we may grow forever adding them thinking they // contatin a memory that's size 0 and never freeing the actual VkImages. if (!SkToBool(fSupportedUsages & UsageFlags::kStencilAttachment) && !SkToBool(fSupportedUsages & UsageFlags::kTexture)) { auto isProtected = this->isProtected() ? GrProtected::kYes : GrProtected::kNo; ComputeScratchKey(*this->getGpu()->caps(), this->backendFormat(), this->dimensions(), fSupportedUsages, this->numSamples(), this->mipmapped(), isProtected, fMemoryless, key); } }