xref: /aosp_15_r20/external/skia/src/gpu/graphite/dawn/DawnTexture.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1 /*
2  * Copyright 2022 Google LLC
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/graphite/dawn/DawnTexture.h"
9 
10 #include "include/core/SkTraceMemoryDump.h"
11 #include "include/gpu/MutableTextureState.h"
12 #include "include/gpu/graphite/dawn/DawnTypes.h"
13 #include "src/core/SkMipmap.h"
14 #include "src/gpu/graphite/Log.h"
15 #include "src/gpu/graphite/TextureUtils.h"
16 #include "src/gpu/graphite/dawn/DawnCaps.h"
17 #include "src/gpu/graphite/dawn/DawnGraphiteTypesPriv.h"
18 #include "src/gpu/graphite/dawn/DawnGraphiteUtilsPriv.h"
19 #include "src/gpu/graphite/dawn/DawnSharedContext.h"
20 
21 namespace skgpu::graphite {
22 
MakeDawnTexture(const DawnSharedContext * sharedContext,SkISize dimensions,const TextureInfo & info)23 wgpu::Texture DawnTexture::MakeDawnTexture(const DawnSharedContext* sharedContext,
24                                            SkISize dimensions,
25                                            const TextureInfo& info) {
26     const Caps* caps = sharedContext->caps();
27     if (dimensions.width() > caps->maxTextureSize() ||
28         dimensions.height() > caps->maxTextureSize()) {
29         SKGPU_LOG_E("Texture creation failure: dimensions %d x %d too large.",
30                     dimensions.width(), dimensions.height());
31         return {};
32     }
33 
34     const DawnTextureSpec dawnSpec = TextureInfos::GetDawnTextureSpec(info);
35 
36     if (dawnSpec.fUsage & wgpu::TextureUsage::TextureBinding && !caps->isTexturable(info)) {
37         return {};
38     }
39 
40     if (dawnSpec.fUsage & wgpu::TextureUsage::RenderAttachment &&
41         !(caps->isRenderable(info) || DawnFormatIsDepthOrStencil(dawnSpec.fFormat))) {
42         return {};
43     }
44 
45     if (dawnSpec.fUsage & wgpu::TextureUsage::StorageBinding && !caps->isStorage(info)) {
46         return {};
47     }
48 
49 #if !defined(__EMSCRIPTEN__)
50     // If a non-default YCbCr descriptor is provided, either the vkFormat or the externalFormat must
51     // be defined.
52     if (ycbcrUtils::DawnDescriptorIsValid(dawnSpec.fYcbcrVkDescriptor) &&
53         dawnSpec.fYcbcrVkDescriptor.vkFormat == 0 &&
54         dawnSpec.fYcbcrVkDescriptor.externalFormat == 0) {
55         return {};
56     }
57 #endif
58 
59     int numMipLevels = 1;
60     if (info.mipmapped() == Mipmapped::kYes) {
61         numMipLevels = SkMipmap::ComputeLevelCount(dimensions.width(), dimensions.height()) + 1;
62     }
63 
64     wgpu::TextureDescriptor desc;
65     desc.usage                      = dawnSpec.fUsage;
66     desc.dimension                  = wgpu::TextureDimension::e2D;
67     desc.size.width                 = dimensions.width();
68     desc.size.height                = dimensions.height();
69     desc.size.depthOrArrayLayers    = 1;
70     desc.format                     = dawnSpec.fFormat;
71     desc.mipLevelCount              = numMipLevels;
72     desc.sampleCount                = info.numSamples();
73     desc.viewFormatCount            = 0;
74     desc.viewFormats                = nullptr;
75 
76     auto texture = sharedContext->device().CreateTexture(&desc);
77     if (!texture) {
78         return {};
79     }
80 
81     return texture;
82 }
83 
DawnTexture(const DawnSharedContext * sharedContext,SkISize dimensions,const TextureInfo & info,wgpu::Texture texture,wgpu::TextureView sampleTextureView,wgpu::TextureView renderTextureView,Ownership ownership,skgpu::Budgeted budgeted)84 DawnTexture::DawnTexture(const DawnSharedContext* sharedContext,
85                          SkISize dimensions,
86                          const TextureInfo& info,
87                          wgpu::Texture texture,
88                          wgpu::TextureView sampleTextureView,
89                          wgpu::TextureView renderTextureView,
90                          Ownership ownership,
91                          skgpu::Budgeted budgeted)
92         : Texture(sharedContext,
93                   dimensions,
94                   info,
95                   /*mutableState=*/nullptr,
96                   ownership,
97                   budgeted)
98         , fTexture(std::move(texture))
99         , fSampleTextureView(std::move(sampleTextureView))
100         , fRenderTextureView(std::move(renderTextureView)) {}
101 
102 // static
CreateTextureViews(const wgpu::Texture & texture,const TextureInfo & info)103 std::pair<wgpu::TextureView, wgpu::TextureView> DawnTexture::CreateTextureViews(
104         const wgpu::Texture& texture, const TextureInfo& info) {
105     const DawnTextureSpec dawnSpec = TextureInfos::GetDawnTextureSpec(info);
106     const auto aspect = dawnSpec.fAspect;
107     if (aspect == wgpu::TextureAspect::All) {
108         wgpu::TextureViewDescriptor viewDesc = {};
109         viewDesc.dimension = wgpu::TextureViewDimension::e2D;
110         viewDesc.baseArrayLayer = dawnSpec.fSlice;
111         viewDesc.arrayLayerCount = 1;
112 #if !defined(__EMSCRIPTEN__)
113         // Ensure that the TextureView is configured to use YCbCr sampling if the Texture is
114         // doing so.
115         const wgpu::YCbCrVkDescriptor& ycbcrDesc = dawnSpec.fYcbcrVkDescriptor;
116         if (ycbcrUtils::DawnDescriptorIsValid(ycbcrDesc)) {
117             viewDesc.nextInChain = &ycbcrDesc;
118         }
119 #endif
120         wgpu::TextureView sampleTextureView = texture.CreateView(&viewDesc);
121         wgpu::TextureView renderTextureView;
122         if (info.mipmapped() == Mipmapped::kYes) {
123             viewDesc.baseMipLevel = 0;
124             viewDesc.mipLevelCount = 1;
125             renderTextureView = texture.CreateView(&viewDesc);
126         } else {
127             renderTextureView = sampleTextureView;
128         }
129         return {sampleTextureView, renderTextureView};
130     }
131 
132 #if defined(__EMSCRIPTEN__)
133     SkASSERT(false);
134     return {};
135 #else
136     SkASSERT(aspect == wgpu::TextureAspect::Plane0Only ||
137              aspect == wgpu::TextureAspect::Plane1Only ||
138              aspect == wgpu::TextureAspect::Plane2Only);
139     wgpu::TextureView planeTextureView;
140     wgpu::TextureViewDescriptor planeViewDesc = {};
141 
142     planeViewDesc.format = dawnSpec.fViewFormat;
143     planeViewDesc.dimension = wgpu::TextureViewDimension::e2D;
144     planeViewDesc.aspect = aspect;
145     planeViewDesc.baseArrayLayer = dawnSpec.fSlice;
146     planeViewDesc.arrayLayerCount = 1;
147     planeTextureView = texture.CreateView(&planeViewDesc);
148     return {planeTextureView, planeTextureView};
149 #endif
150 }
151 
Make(const DawnSharedContext * sharedContext,SkISize dimensions,const TextureInfo & info,skgpu::Budgeted budgeted)152 sk_sp<Texture> DawnTexture::Make(const DawnSharedContext* sharedContext,
153                                  SkISize dimensions,
154                                  const TextureInfo& info,
155                                  skgpu::Budgeted budgeted) {
156     auto texture = MakeDawnTexture(sharedContext, dimensions, info);
157     if (!texture) {
158         return {};
159     }
160     auto [sampleTextureView, renderTextureView] = CreateTextureViews(texture, info);
161     return sk_sp<Texture>(new DawnTexture(sharedContext,
162                                           dimensions,
163                                           info,
164                                           std::move(texture),
165                                           std::move(sampleTextureView),
166                                           std::move(renderTextureView),
167                                           Ownership::kOwned,
168                                           budgeted));
169 }
170 
MakeWrapped(const DawnSharedContext * sharedContext,SkISize dimensions,const TextureInfo & info,wgpu::Texture texture)171 sk_sp<Texture> DawnTexture::MakeWrapped(const DawnSharedContext* sharedContext,
172                                         SkISize dimensions,
173                                         const TextureInfo& info,
174                                         wgpu::Texture texture) {
175     if (!texture) {
176         SKGPU_LOG_E("No valid texture passed into MakeWrapped\n");
177         return {};
178     }
179 
180     auto [sampleTextureView, renderTextureView] = CreateTextureViews(texture, info);
181     return sk_sp<Texture>(new DawnTexture(sharedContext,
182                                           dimensions,
183                                           info,
184                                           std::move(texture),
185                                           std::move(sampleTextureView),
186                                           std::move(renderTextureView),
187                                           Ownership::kWrapped,
188                                           skgpu::Budgeted::kNo));
189 }
190 
MakeWrapped(const DawnSharedContext * sharedContext,SkISize dimensions,const TextureInfo & info,const wgpu::TextureView & textureView)191 sk_sp<Texture> DawnTexture::MakeWrapped(const DawnSharedContext* sharedContext,
192                                         SkISize dimensions,
193                                         const TextureInfo& info,
194                                         const wgpu::TextureView& textureView) {
195     if (!textureView) {
196         SKGPU_LOG_E("No valid texture view passed into MakeWrapped\n");
197         return {};
198     }
199     return sk_sp<Texture>(new DawnTexture(sharedContext,
200                                           dimensions,
201                                           info,
202                                           /*texture=*/nullptr,
203                                           /*sampleTextureView=*/textureView,
204                                           /*renderTextureView=*/textureView,
205                                           Ownership::kWrapped,
206                                           skgpu::Budgeted::kNo));
207 }
208 
freeGpuData()209 void DawnTexture::freeGpuData() {
210     if (this->ownership() != Ownership::kWrapped && fTexture) {
211         // Destroy the texture even if it is still referenced by other BindGroup or views.
212         // Graphite should already guarantee that all command buffers using this texture (indirectly
213         // via BindGroup or views) are already completed.
214         fTexture.Destroy();
215     }
216     fTexture = nullptr;
217     fSampleTextureView = nullptr;
218     fRenderTextureView = nullptr;
219 }
220 
setBackendLabel(char const * label)221 void DawnTexture::setBackendLabel(char const* label) {
222     if (!sharedContext()->caps()->setBackendLabels()) {
223         return;
224     }
225     SkASSERT(label);
226     // Wrapped texture views won't have an associated texture here.
227     if (fTexture) {
228         fTexture.SetLabel(label);
229     }
230     // But we always have the texture views available.
231     SkASSERT(fSampleTextureView);
232     SkASSERT(fRenderTextureView);
233     if (fSampleTextureView.Get() == fRenderTextureView.Get()) {
234         fSampleTextureView.SetLabel(SkStringPrintf("%s_%s", label, "_TextureView").c_str());
235     } else {
236         fSampleTextureView.SetLabel(SkStringPrintf("%s_%s", label, "_SampleTextureView").c_str());
237         fRenderTextureView.SetLabel(SkStringPrintf("%s_%s", label, "_RenderTextureView").c_str());
238     }
239 }
240 
241 } // namespace skgpu::graphite
242 
243