1 /*
2 * Copyright 2011 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/ganesh/GrAttachment.h"
9
10 #include "include/gpu/GpuTypes.h"
11 #include "include/private/base/SkAssert.h"
12 #include "include/private/base/SkTo.h"
13 #include "src/gpu/DataUtils.h"
14 #include "src/gpu/ResourceKey.h"
15 #include "src/gpu/ganesh/GrBackendUtils.h"
16 #include "src/gpu/ganesh/GrCaps.h"
17 #include "src/gpu/ganesh/GrGpu.h"
18
19 enum class SkTextureCompressionType;
20
onGpuMemorySize() const21 size_t GrAttachment::onGpuMemorySize() const {
22 // The GrTexture[RenderTarget] is built up by a bunch of attachments each of which are their
23 // own GrGpuResource. Ideally the GrRenderTarget would not be a GrGpuResource and the GrTexture
24 // would just merge with the new GrSurface/Attachment world. Then we could just depend on each
25 // attachment to give its own size since we don't have GrGpuResources owning other
26 // GrGpuResources. Until we get to that point we need to live in some hybrid world. We will let
27 // the msaa and stencil attachments track their own size because they do get cached separately.
28 // For all GrTexture* based things we will continue to to use the GrTexture* to report size and
29 // the owned attachments will have no size and be uncached.
30 if (!(fSupportedUsages & UsageFlags::kTexture) && fMemoryless == GrMemoryless::kNo) {
31 GrBackendFormat format = this->backendFormat();
32 SkTextureCompressionType compression = GrBackendFormatToCompressionType(format);
33
34 uint64_t size = skgpu::NumCompressedBlocks(compression, this->dimensions());
35 size *= GrBackendFormatBytesPerBlock(this->backendFormat());
36 size *= this->numSamples();
37 return size;
38 }
39 return 0;
40 }
41
dumpMemoryStatistics(SkTraceMemoryDump * traceMemoryDump) const42 void GrAttachment::dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const {
43 SkString type;
44 if (fSupportedUsages == UsageFlags::kStencilAttachment) {
45 type = "StencilAttachment";
46 }
47
48 if (fSupportedUsages & UsageFlags::kTexture) {
49 // This return since the memory should all be handled by the textures
50 return;
51 } else if (fSupportedUsages & UsageFlags::kColorAttachment) {
52 type = "ColorAttachment";
53 }
54
55 SkString resourceName = this->getResourceName();
56 resourceName.append("/attachment");
57 this->dumpMemoryStatisticsPriv(traceMemoryDump, resourceName, type.c_str(), onGpuMemorySize());
58 }
59
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)60 static void build_key(skgpu::ResourceKey::Builder* builder,
61 const GrCaps& caps,
62 const GrBackendFormat& format,
63 SkISize dimensions,
64 GrAttachment::UsageFlags requiredUsage,
65 int sampleCnt,
66 skgpu::Mipmapped mipmapped,
67 GrProtected isProtected,
68 GrMemoryless memoryless) {
69 SkASSERT(!dimensions.isEmpty());
70
71 SkASSERT(static_cast<uint32_t>(isProtected) <= 1);
72 SkASSERT(static_cast<uint32_t>(memoryless) <= 1);
73 SkASSERT(static_cast<uint32_t>(requiredUsage) < (1u << 8));
74 SkASSERT(static_cast<uint32_t>(sampleCnt) < (1u << (32 - 10)));
75
76 uint64_t formatKey = caps.computeFormatKey(format);
77 (*builder)[0] = dimensions.width();
78 (*builder)[1] = dimensions.height();
79 (*builder)[2] = formatKey & 0xFFFFFFFF;
80 (*builder)[3] = (formatKey >> 32) & 0xFFFFFFFF;
81 (*builder)[4] = (static_cast<uint32_t>(isProtected) << 0) |
82 (static_cast<uint32_t>(memoryless) << 1) |
83 (static_cast<uint32_t>(requiredUsage) << 2) |
84 (static_cast<uint32_t>(sampleCnt) << 10);
85 }
86
ComputeSharedAttachmentUniqueKey(const GrCaps & caps,const GrBackendFormat & format,SkISize dimensions,UsageFlags requiredUsage,int sampleCnt,skgpu::Mipmapped mipmapped,GrProtected isProtected,GrMemoryless memoryless,skgpu::UniqueKey * key)87 void GrAttachment::ComputeSharedAttachmentUniqueKey(const GrCaps& caps,
88 const GrBackendFormat& format,
89 SkISize dimensions,
90 UsageFlags requiredUsage,
91 int sampleCnt,
92 skgpu::Mipmapped mipmapped,
93 GrProtected isProtected,
94 GrMemoryless memoryless,
95 skgpu::UniqueKey* key) {
96 static const skgpu::UniqueKey::Domain kDomain = skgpu::UniqueKey::GenerateDomain();
97
98 skgpu::UniqueKey::Builder builder(key, kDomain, 5);
99 build_key(&builder, caps, format, dimensions, requiredUsage, sampleCnt, mipmapped, isProtected,
100 memoryless);
101 }
102
ComputeScratchKey(const GrCaps & caps,const GrBackendFormat & format,SkISize dimensions,UsageFlags requiredUsage,int sampleCnt,skgpu::Mipmapped mipmapped,GrProtected isProtected,GrMemoryless memoryless,skgpu::ScratchKey * key)103 void GrAttachment::ComputeScratchKey(const GrCaps& caps,
104 const GrBackendFormat& format,
105 SkISize dimensions,
106 UsageFlags requiredUsage,
107 int sampleCnt,
108 skgpu::Mipmapped mipmapped,
109 GrProtected isProtected,
110 GrMemoryless memoryless,
111 skgpu::ScratchKey* key) {
112 static const skgpu::ScratchKey::ResourceType kType = skgpu::ScratchKey::GenerateResourceType();
113
114 skgpu::ScratchKey::Builder builder(key, kType, 5);
115 build_key(&builder, caps, format, dimensions, requiredUsage, sampleCnt, mipmapped, isProtected,
116 memoryless);
117 }
118
computeScratchKey(skgpu::ScratchKey * key) const119 void GrAttachment::computeScratchKey(skgpu::ScratchKey* key) const {
120 // We do don't cache GrAttachments as scratch resources when used for stencils or textures. For
121 // stencils we share/cache them with unique keys so that they can be shared. Textures are in a
122 // weird place on the Vulkan backend. Currently, GrVkTexture contains a GrAttachment (GrVkImage)
123 // that actually holds the VkImage. The GrVkTexture is cached as a scratch resource and is
124 // responsible for tracking the gpuMemorySize. Thus we set the size of the texture GrVkImage,
125 // above in onGpuMemorySize, to be zero. Therefore, we can't have the GrVkImage getting cached
126 // separately on its own in the GrResourceCache or we may grow forever adding them thinking they
127 // contatin a memory that's size 0 and never freeing the actual VkImages.
128 if (!SkToBool(fSupportedUsages & UsageFlags::kStencilAttachment) &&
129 !SkToBool(fSupportedUsages & UsageFlags::kTexture)) {
130 auto isProtected = this->isProtected() ? GrProtected::kYes : GrProtected::kNo;
131 ComputeScratchKey(*this->getGpu()->caps(),
132 this->backendFormat(),
133 this->dimensions(),
134 fSupportedUsages,
135 this->numSamples(),
136 this->mipmapped(),
137 isProtected,
138 fMemoryless,
139 key);
140 }
141 }
142