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