blob: 496ca1093ca0835558c181fb8c36585edb624e77 [file] [log] [blame]
Corentin Wallez4a9ef4e2018-07-18 11:40:26 +02001// Copyright 2017 The Dawn Authors
Corentin Wallez0ba55502017-06-14 15:46:59 -04002//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
Corentin Wallezd37523f2018-07-24 13:53:51 +020015#include "dawn_native/metal/TextureMTL.h"
Corentin Wallez0ba55502017-06-14 15:46:59 -040016
Austin Eng0d661982020-01-16 00:12:10 +000017#include "common/Constants.h"
18#include "common/Math.h"
Corentin Wallezb495e482019-09-18 04:32:52 +000019#include "common/Platform.h"
Austin Eng0d661982020-01-16 00:12:10 +000020#include "dawn_native/DynamicUploader.h"
Austin Eng2cf5a082020-08-06 17:00:29 +000021#include "dawn_native/EnumMaskIterator.h"
Corentin Wallezd37523f2018-07-24 13:53:51 +020022#include "dawn_native/metal/DeviceMTL.h"
Austin Eng0d661982020-01-16 00:12:10 +000023#include "dawn_native/metal/StagingBufferMTL.h"
Austin Eng2cf5a082020-08-06 17:00:29 +000024#include "dawn_native/metal/UtilsMetal.h"
Corentin Wallez0ba55502017-06-14 15:46:59 -040025
Corentin Wallezc85ef792020-04-29 21:07:21 +000026#include <CoreVideo/CVPixelBuffer.h>
27
Corentin Wallez49a65d02018-07-24 16:45:45 +020028namespace dawn_native { namespace metal {
Corentin Wallez8308b1c2017-07-03 23:02:49 -040029
Austin Eng476e5cb2017-08-03 12:17:14 -040030 namespace {
Corentin Wallez1f6c8c42019-10-23 11:57:41 +000031 bool UsageNeedsTextureView(wgpu::TextureUsage usage) {
32 constexpr wgpu::TextureUsage kUsageNeedsTextureView =
Brandon Jones27e17a62021-08-10 04:07:37 +000033 wgpu::TextureUsage::StorageBinding | wgpu::TextureUsage::TextureBinding;
Jiawei Shao5dee56f2018-12-29 10:47:28 +000034 return usage & kUsageNeedsTextureView;
35 }
36
Austin Eng75c50672021-06-24 02:01:46 +000037 MTLTextureUsage MetalTextureUsage(const Format& format,
38 wgpu::TextureUsage usage,
39 uint32_t sampleCount) {
Corentin Wallezf58d84d2017-11-24 14:12:44 -050040 MTLTextureUsage result = MTLTextureUsageUnknown; // This is 0
Corentin Wallez8308b1c2017-07-03 23:02:49 -040041
Brandon Jones27e17a62021-08-10 04:07:37 +000042 if (usage & (wgpu::TextureUsage::StorageBinding)) {
Corentin Wallez8308b1c2017-07-03 23:02:49 -040043 result |= MTLTextureUsageShaderWrite | MTLTextureUsageShaderRead;
44 }
45
Brandon Jones27e17a62021-08-10 04:07:37 +000046 if (usage & (wgpu::TextureUsage::TextureBinding)) {
Corentin Wallez8308b1c2017-07-03 23:02:49 -040047 result |= MTLTextureUsageShaderRead;
Austin Enga0f17252020-11-04 15:27:11 +000048
49 // For sampling stencil aspect of combined depth/stencil. See TextureView
50 // constructor.
51 if (@available(macOS 10.12, iOS 10.0, *)) {
52 if (IsSubset(Aspect::Depth | Aspect::Stencil, format.aspects)) {
53 result |= MTLTextureUsagePixelFormatView;
54 }
55 }
Corentin Wallez8308b1c2017-07-03 23:02:49 -040056 }
57
Austin Eng75c50672021-06-24 02:01:46 +000058 // MTLTextureUsageRenderTarget is needed to clear multisample textures.
59 if (usage & (wgpu::TextureUsage::RenderAttachment) || sampleCount > 1) {
Corentin Wallez8308b1c2017-07-03 23:02:49 -040060 result |= MTLTextureUsageRenderTarget;
61 }
62
63 return result;
64 }
65
Corentin Wallez1f6c8c42019-10-23 11:57:41 +000066 MTLTextureType MetalTextureViewType(wgpu::TextureViewDimension dimension,
Jiawei Shao865cad82019-04-09 08:04:59 +000067 unsigned int sampleCount) {
Jiawei Shaoe8d12b42018-10-26 06:29:38 +000068 switch (dimension) {
Corentin Wallez1f6c8c42019-10-23 11:57:41 +000069 case wgpu::TextureViewDimension::e2D:
Jiawei Shao865cad82019-04-09 08:04:59 +000070 return (sampleCount > 1) ? MTLTextureType2DMultisample : MTLTextureType2D;
Corentin Wallez1f6c8c42019-10-23 11:57:41 +000071 case wgpu::TextureViewDimension::e2DArray:
Jiawei Shaoe8d12b42018-10-26 06:29:38 +000072 return MTLTextureType2DArray;
Corentin Wallez1f6c8c42019-10-23 11:57:41 +000073 case wgpu::TextureViewDimension::Cube:
Jiawei Shao5ab84ec2018-11-16 12:11:20 +000074 return MTLTextureTypeCube;
Corentin Wallez1f6c8c42019-10-23 11:57:41 +000075 case wgpu::TextureViewDimension::CubeArray:
Jiawei Shao5ab84ec2018-11-16 12:11:20 +000076 return MTLTextureTypeCubeArray;
Yunchao He1b9bcfc2021-02-03 16:36:59 +000077 case wgpu::TextureViewDimension::e3D:
78 return MTLTextureType3D;
Corentin Wallezeec9edf2020-09-24 14:56:50 +000079
80 case wgpu::TextureViewDimension::e1D:
Corentin Wallezeec9edf2020-09-24 14:56:50 +000081 case wgpu::TextureViewDimension::Undefined:
Jiawei Shaoe8d12b42018-10-26 06:29:38 +000082 UNREACHABLE();
Jiawei Shaoe8d12b42018-10-26 06:29:38 +000083 }
84 }
Jiawei Shao5dee56f2018-12-29 10:47:28 +000085
86 bool RequiresCreatingNewTextureView(const TextureBase* texture,
87 const TextureViewDescriptor* textureViewDescriptor) {
Corentin Walleza92f83b2019-06-21 10:16:15 +000088 if (texture->GetFormat().format != textureViewDescriptor->format) {
Jiawei Shao5dee56f2018-12-29 10:47:28 +000089 return true;
90 }
91
Jiawei Shao20301662019-02-21 00:45:19 +000092 if (texture->GetArrayLayers() != textureViewDescriptor->arrayLayerCount) {
Jiawei Shao5dee56f2018-12-29 10:47:28 +000093 return true;
94 }
95
Jiawei Shao20301662019-02-21 00:45:19 +000096 if (texture->GetNumMipLevels() != textureViewDescriptor->mipLevelCount) {
Jiawei Shao5dee56f2018-12-29 10:47:28 +000097 return true;
98 }
99
Austin Enga0f17252020-11-04 15:27:11 +0000100 if (IsSubset(Aspect::Depth | Aspect::Stencil, texture->GetFormat().aspects) &&
101 textureViewDescriptor->aspect == wgpu::TextureAspect::StencilOnly) {
102 return true;
103 }
104
Jiawei Shao5dee56f2018-12-29 10:47:28 +0000105 switch (textureViewDescriptor->dimension) {
Corentin Wallez1f6c8c42019-10-23 11:57:41 +0000106 case wgpu::TextureViewDimension::Cube:
107 case wgpu::TextureViewDimension::CubeArray:
Jiawei Shao5dee56f2018-12-29 10:47:28 +0000108 return true;
109 default:
110 break;
111 }
112
113 return false;
114 }
Corentin Wallez0cdf9e02019-03-01 12:01:18 +0000115
Yancf0e4fc2022-01-06 09:01:58 +0000116 // Metal only allows format reinterpretation to happen on swizzle pattern or conversion
117 // between linear space and sRGB without setting MTLTextureUsagePixelFormatView flag. For
118 // example, creating bgra8Unorm texture view on rgba8Unorm texture or creating
119 // rgba8Unorm_srgb texture view on rgab8Unorm texture.
120 bool AllowFormatReinterpretationWithoutFlag(MTLPixelFormat origin,
121 MTLPixelFormat reinterpretation) {
122 switch (origin) {
123 case MTLPixelFormatRGBA8Unorm:
124 return reinterpretation == MTLPixelFormatBGRA8Unorm ||
125 reinterpretation == MTLPixelFormatRGBA8Unorm_sRGB;
126 case MTLPixelFormatBGRA8Unorm:
127 return reinterpretation == MTLPixelFormatRGBA8Unorm ||
128 reinterpretation == MTLPixelFormatBGRA8Unorm_sRGB;
129 case MTLPixelFormatRGBA8Unorm_sRGB:
130 return reinterpretation == MTLPixelFormatBGRA8Unorm_sRGB ||
131 reinterpretation == MTLPixelFormatRGBA8Unorm;
132 case MTLPixelFormatBGRA8Unorm_sRGB:
133 return reinterpretation == MTLPixelFormatRGBA8Unorm_sRGB ||
134 reinterpretation == MTLPixelFormatBGRA8Unorm;
135#if defined(DAWN_PLATFORM_MACOS)
136 case MTLPixelFormatBC1_RGBA:
137 return reinterpretation == MTLPixelFormatBC1_RGBA_sRGB;
138 case MTLPixelFormatBC1_RGBA_sRGB:
139 return reinterpretation == MTLPixelFormatBC1_RGBA;
140 case MTLPixelFormatBC2_RGBA:
141 return reinterpretation == MTLPixelFormatBC2_RGBA_sRGB;
142 case MTLPixelFormatBC2_RGBA_sRGB:
143 return reinterpretation == MTLPixelFormatBC2_RGBA;
144 case MTLPixelFormatBC3_RGBA:
145 return reinterpretation == MTLPixelFormatBC3_RGBA_sRGB;
146 case MTLPixelFormatBC3_RGBA_sRGB:
147 return reinterpretation == MTLPixelFormatBC3_RGBA;
148 case MTLPixelFormatBC7_RGBAUnorm:
149 return reinterpretation == MTLPixelFormatBC7_RGBAUnorm_sRGB;
150 case MTLPixelFormatBC7_RGBAUnorm_sRGB:
151 return reinterpretation == MTLPixelFormatBC7_RGBAUnorm;
152#endif
153
154 default:
155 return false;
156 }
157 }
158
Corentin Wallez1f6c8c42019-10-23 11:57:41 +0000159 ResultOrError<wgpu::TextureFormat> GetFormatEquivalentToIOSurfaceFormat(uint32_t format) {
Corentin Wallez0cdf9e02019-03-01 12:01:18 +0000160 switch (format) {
Corentin Wallezc85ef792020-04-29 21:07:21 +0000161 case kCVPixelFormatType_32RGBA:
Corentin Wallez1f6c8c42019-10-23 11:57:41 +0000162 return wgpu::TextureFormat::RGBA8Unorm;
Corentin Wallezc85ef792020-04-29 21:07:21 +0000163 case kCVPixelFormatType_32BGRA:
Corentin Wallez1f6c8c42019-10-23 11:57:41 +0000164 return wgpu::TextureFormat::BGRA8Unorm;
Corentin Wallezc85ef792020-04-29 21:07:21 +0000165 case kCVPixelFormatType_TwoComponent8:
Corentin Wallez1f6c8c42019-10-23 11:57:41 +0000166 return wgpu::TextureFormat::RG8Unorm;
Corentin Wallezc85ef792020-04-29 21:07:21 +0000167 case kCVPixelFormatType_OneComponent8:
Corentin Wallez1f6c8c42019-10-23 11:57:41 +0000168 return wgpu::TextureFormat::R8Unorm;
Corentin Wallez0cdf9e02019-03-01 12:01:18 +0000169 default:
Brandon Joneseb0d9002021-10-22 17:39:20 +0000170 return DAWN_FORMAT_VALIDATION_ERROR("Unsupported IOSurface format (%x).",
171 format);
Corentin Wallez0cdf9e02019-03-01 12:01:18 +0000172 }
173 }
Corentin Wallezb495e482019-09-18 04:32:52 +0000174
175#if defined(DAWN_PLATFORM_MACOS)
176 MTLStorageMode kIOSurfaceStorageMode = MTLStorageModeManaged;
177#elif defined(DAWN_PLATFORM_IOS)
178 MTLStorageMode kIOSurfaceStorageMode = MTLStorageModePrivate;
179#else
180# error "Unsupported Apple platform."
181#endif
Corentin Wallez0cdf9e02019-03-01 12:01:18 +0000182 }
183
Corentin Wallez1f6c8c42019-10-23 11:57:41 +0000184 MTLPixelFormat MetalPixelFormat(wgpu::TextureFormat format) {
Corentin Wallez0cdf9e02019-03-01 12:01:18 +0000185 switch (format) {
Corentin Wallez1f6c8c42019-10-23 11:57:41 +0000186 case wgpu::TextureFormat::R8Unorm:
Corentin Wallez0cdf9e02019-03-01 12:01:18 +0000187 return MTLPixelFormatR8Unorm;
Corentin Wallez1f6c8c42019-10-23 11:57:41 +0000188 case wgpu::TextureFormat::R8Snorm:
Corentin Wallez78430762019-07-08 09:28:51 +0000189 return MTLPixelFormatR8Snorm;
Corentin Wallez1f6c8c42019-10-23 11:57:41 +0000190 case wgpu::TextureFormat::R8Uint:
Corentin Wallez0cdf9e02019-03-01 12:01:18 +0000191 return MTLPixelFormatR8Uint;
Corentin Wallez1f6c8c42019-10-23 11:57:41 +0000192 case wgpu::TextureFormat::R8Sint:
Corentin Wallez78430762019-07-08 09:28:51 +0000193 return MTLPixelFormatR8Sint;
194
Corentin Wallez1f6c8c42019-10-23 11:57:41 +0000195 case wgpu::TextureFormat::R16Uint:
Corentin Wallez78430762019-07-08 09:28:51 +0000196 return MTLPixelFormatR16Uint;
Corentin Wallez1f6c8c42019-10-23 11:57:41 +0000197 case wgpu::TextureFormat::R16Sint:
Corentin Wallez78430762019-07-08 09:28:51 +0000198 return MTLPixelFormatR16Sint;
Corentin Wallez1f6c8c42019-10-23 11:57:41 +0000199 case wgpu::TextureFormat::R16Float:
Corentin Wallez78430762019-07-08 09:28:51 +0000200 return MTLPixelFormatR16Float;
Corentin Wallez1f6c8c42019-10-23 11:57:41 +0000201 case wgpu::TextureFormat::RG8Unorm:
Corentin Wallez78430762019-07-08 09:28:51 +0000202 return MTLPixelFormatRG8Unorm;
Corentin Wallez1f6c8c42019-10-23 11:57:41 +0000203 case wgpu::TextureFormat::RG8Snorm:
Corentin Wallez78430762019-07-08 09:28:51 +0000204 return MTLPixelFormatRG8Snorm;
Corentin Wallez1f6c8c42019-10-23 11:57:41 +0000205 case wgpu::TextureFormat::RG8Uint:
Corentin Wallez78430762019-07-08 09:28:51 +0000206 return MTLPixelFormatRG8Uint;
Corentin Wallez1f6c8c42019-10-23 11:57:41 +0000207 case wgpu::TextureFormat::RG8Sint:
Corentin Wallez78430762019-07-08 09:28:51 +0000208 return MTLPixelFormatRG8Sint;
209
Corentin Wallez1f6c8c42019-10-23 11:57:41 +0000210 case wgpu::TextureFormat::R32Uint:
Corentin Wallez78430762019-07-08 09:28:51 +0000211 return MTLPixelFormatR32Uint;
Corentin Wallez1f6c8c42019-10-23 11:57:41 +0000212 case wgpu::TextureFormat::R32Sint:
Corentin Wallez78430762019-07-08 09:28:51 +0000213 return MTLPixelFormatR32Sint;
Corentin Wallez1f6c8c42019-10-23 11:57:41 +0000214 case wgpu::TextureFormat::R32Float:
Corentin Wallez78430762019-07-08 09:28:51 +0000215 return MTLPixelFormatR32Float;
Corentin Wallez1f6c8c42019-10-23 11:57:41 +0000216 case wgpu::TextureFormat::RG16Uint:
Corentin Wallez78430762019-07-08 09:28:51 +0000217 return MTLPixelFormatRG16Uint;
Corentin Wallez1f6c8c42019-10-23 11:57:41 +0000218 case wgpu::TextureFormat::RG16Sint:
Corentin Wallez78430762019-07-08 09:28:51 +0000219 return MTLPixelFormatRG16Sint;
Corentin Wallez1f6c8c42019-10-23 11:57:41 +0000220 case wgpu::TextureFormat::RG16Float:
Corentin Wallez78430762019-07-08 09:28:51 +0000221 return MTLPixelFormatRG16Float;
Corentin Wallez1f6c8c42019-10-23 11:57:41 +0000222 case wgpu::TextureFormat::RGBA8Unorm:
Corentin Wallez78430762019-07-08 09:28:51 +0000223 return MTLPixelFormatRGBA8Unorm;
Corentin Wallez1f6c8c42019-10-23 11:57:41 +0000224 case wgpu::TextureFormat::RGBA8UnormSrgb:
Corentin Wallez78430762019-07-08 09:28:51 +0000225 return MTLPixelFormatRGBA8Unorm_sRGB;
Corentin Wallez1f6c8c42019-10-23 11:57:41 +0000226 case wgpu::TextureFormat::RGBA8Snorm:
Corentin Wallez78430762019-07-08 09:28:51 +0000227 return MTLPixelFormatRGBA8Snorm;
Corentin Wallez1f6c8c42019-10-23 11:57:41 +0000228 case wgpu::TextureFormat::RGBA8Uint:
Corentin Wallez78430762019-07-08 09:28:51 +0000229 return MTLPixelFormatRGBA8Uint;
Corentin Wallez1f6c8c42019-10-23 11:57:41 +0000230 case wgpu::TextureFormat::RGBA8Sint:
Corentin Wallez78430762019-07-08 09:28:51 +0000231 return MTLPixelFormatRGBA8Sint;
Corentin Wallez1f6c8c42019-10-23 11:57:41 +0000232 case wgpu::TextureFormat::BGRA8Unorm:
Corentin Wallez0cdf9e02019-03-01 12:01:18 +0000233 return MTLPixelFormatBGRA8Unorm;
Corentin Wallez1f6c8c42019-10-23 11:57:41 +0000234 case wgpu::TextureFormat::BGRA8UnormSrgb:
Corentin Wallez78430762019-07-08 09:28:51 +0000235 return MTLPixelFormatBGRA8Unorm_sRGB;
Corentin Wallez1f6c8c42019-10-23 11:57:41 +0000236 case wgpu::TextureFormat::RGB10A2Unorm:
Corentin Wallez78430762019-07-08 09:28:51 +0000237 return MTLPixelFormatRGB10A2Unorm;
Corentin Wallez2f6e4ec2020-08-19 21:51:20 +0000238 case wgpu::TextureFormat::RG11B10Ufloat:
Corentin Wallez78430762019-07-08 09:28:51 +0000239 return MTLPixelFormatRG11B10Float;
Corentin Wallez2f6e4ec2020-08-19 21:51:20 +0000240 case wgpu::TextureFormat::RGB9E5Ufloat:
241 return MTLPixelFormatRGB9E5Float;
Corentin Wallez78430762019-07-08 09:28:51 +0000242
Corentin Wallez1f6c8c42019-10-23 11:57:41 +0000243 case wgpu::TextureFormat::RG32Uint:
Corentin Wallez78430762019-07-08 09:28:51 +0000244 return MTLPixelFormatRG32Uint;
Corentin Wallez1f6c8c42019-10-23 11:57:41 +0000245 case wgpu::TextureFormat::RG32Sint:
Corentin Wallez78430762019-07-08 09:28:51 +0000246 return MTLPixelFormatRG32Sint;
Corentin Wallez1f6c8c42019-10-23 11:57:41 +0000247 case wgpu::TextureFormat::RG32Float:
Corentin Wallez78430762019-07-08 09:28:51 +0000248 return MTLPixelFormatRG32Float;
Corentin Wallez1f6c8c42019-10-23 11:57:41 +0000249 case wgpu::TextureFormat::RGBA16Uint:
Corentin Wallez78430762019-07-08 09:28:51 +0000250 return MTLPixelFormatRGBA16Uint;
Corentin Wallez1f6c8c42019-10-23 11:57:41 +0000251 case wgpu::TextureFormat::RGBA16Sint:
Corentin Wallez78430762019-07-08 09:28:51 +0000252 return MTLPixelFormatRGBA16Sint;
Corentin Wallez1f6c8c42019-10-23 11:57:41 +0000253 case wgpu::TextureFormat::RGBA16Float:
Corentin Wallez78430762019-07-08 09:28:51 +0000254 return MTLPixelFormatRGBA16Float;
255
Corentin Wallez1f6c8c42019-10-23 11:57:41 +0000256 case wgpu::TextureFormat::RGBA32Uint:
Corentin Wallez78430762019-07-08 09:28:51 +0000257 return MTLPixelFormatRGBA32Uint;
Corentin Wallez1f6c8c42019-10-23 11:57:41 +0000258 case wgpu::TextureFormat::RGBA32Sint:
Corentin Wallez78430762019-07-08 09:28:51 +0000259 return MTLPixelFormatRGBA32Sint;
Corentin Wallez1f6c8c42019-10-23 11:57:41 +0000260 case wgpu::TextureFormat::RGBA32Float:
Corentin Wallez78430762019-07-08 09:28:51 +0000261 return MTLPixelFormatRGBA32Float;
262
Corentin Wallez1f6c8c42019-10-23 11:57:41 +0000263 case wgpu::TextureFormat::Depth32Float:
Corentin Wallez78430762019-07-08 09:28:51 +0000264 return MTLPixelFormatDepth32Float;
Corentin Wallez1f6c8c42019-10-23 11:57:41 +0000265 case wgpu::TextureFormat::Depth24Plus:
Corentin Wallez78430762019-07-08 09:28:51 +0000266 return MTLPixelFormatDepth32Float;
Corentin Wallez1f6c8c42019-10-23 11:57:41 +0000267 case wgpu::TextureFormat::Depth24PlusStencil8:
Li Hao538d8d52022-01-05 01:31:16 +0000268 case wgpu::TextureFormat::Depth32FloatStencil8:
Corentin Wallez0cdf9e02019-03-01 12:01:18 +0000269 return MTLPixelFormatDepth32Float_Stencil8;
Dawn Autorollerd0effc02021-11-03 22:48:34 +0000270 case wgpu::TextureFormat::Depth16Unorm:
271 if (@available(macOS 10.12, iOS 13.0, *)) {
272 return MTLPixelFormatDepth16Unorm;
273 } else {
274 // TODO (dawn:1181): Allow non-conformant implementation on macOS 10.11
275 UNREACHABLE();
276 }
Corentin Wallez78430762019-07-08 09:28:51 +0000277
Corentin Wallezb629c502019-10-08 07:44:21 +0000278#if defined(DAWN_PLATFORM_MACOS)
Li Hao538d8d52022-01-05 01:31:16 +0000279 case wgpu::TextureFormat::Depth24UnormStencil8:
280 return MTLPixelFormatDepth24Unorm_Stencil8;
281
Corentin Wallez1f6c8c42019-10-23 11:57:41 +0000282 case wgpu::TextureFormat::BC1RGBAUnorm:
Jiawei Shao55809702019-07-17 00:00:10 +0000283 return MTLPixelFormatBC1_RGBA;
Corentin Wallez1f6c8c42019-10-23 11:57:41 +0000284 case wgpu::TextureFormat::BC1RGBAUnormSrgb:
Jiawei Shao55809702019-07-17 00:00:10 +0000285 return MTLPixelFormatBC1_RGBA_sRGB;
Corentin Wallez1f6c8c42019-10-23 11:57:41 +0000286 case wgpu::TextureFormat::BC2RGBAUnorm:
Jiawei Shao55809702019-07-17 00:00:10 +0000287 return MTLPixelFormatBC2_RGBA;
Corentin Wallez1f6c8c42019-10-23 11:57:41 +0000288 case wgpu::TextureFormat::BC2RGBAUnormSrgb:
Jiawei Shao55809702019-07-17 00:00:10 +0000289 return MTLPixelFormatBC2_RGBA_sRGB;
Corentin Wallez1f6c8c42019-10-23 11:57:41 +0000290 case wgpu::TextureFormat::BC3RGBAUnorm:
Jiawei Shao55809702019-07-17 00:00:10 +0000291 return MTLPixelFormatBC3_RGBA;
Corentin Wallez1f6c8c42019-10-23 11:57:41 +0000292 case wgpu::TextureFormat::BC3RGBAUnormSrgb:
Jiawei Shao55809702019-07-17 00:00:10 +0000293 return MTLPixelFormatBC3_RGBA_sRGB;
Corentin Wallez1f6c8c42019-10-23 11:57:41 +0000294 case wgpu::TextureFormat::BC4RSnorm:
Jiawei Shao55809702019-07-17 00:00:10 +0000295 return MTLPixelFormatBC4_RSnorm;
Corentin Wallez1f6c8c42019-10-23 11:57:41 +0000296 case wgpu::TextureFormat::BC4RUnorm:
Jiawei Shao55809702019-07-17 00:00:10 +0000297 return MTLPixelFormatBC4_RUnorm;
Corentin Wallez1f6c8c42019-10-23 11:57:41 +0000298 case wgpu::TextureFormat::BC5RGSnorm:
Jiawei Shaoea2d5582019-07-10 23:58:13 +0000299 return MTLPixelFormatBC5_RGSnorm;
Corentin Wallez1f6c8c42019-10-23 11:57:41 +0000300 case wgpu::TextureFormat::BC5RGUnorm:
Jiawei Shaoea2d5582019-07-10 23:58:13 +0000301 return MTLPixelFormatBC5_RGUnorm;
Corentin Wallez498d5ea2020-09-10 08:48:57 +0000302 case wgpu::TextureFormat::BC6HRGBFloat:
Jiawei Shao55809702019-07-17 00:00:10 +0000303 return MTLPixelFormatBC6H_RGBFloat;
Corentin Wallez1f6c8c42019-10-23 11:57:41 +0000304 case wgpu::TextureFormat::BC6HRGBUfloat:
Jiawei Shao55809702019-07-17 00:00:10 +0000305 return MTLPixelFormatBC6H_RGBUfloat;
Corentin Wallez1f6c8c42019-10-23 11:57:41 +0000306 case wgpu::TextureFormat::BC7RGBAUnorm:
Jiawei Shao55809702019-07-17 00:00:10 +0000307 return MTLPixelFormatBC7_RGBAUnorm;
Corentin Wallez1f6c8c42019-10-23 11:57:41 +0000308 case wgpu::TextureFormat::BC7RGBAUnormSrgb:
Jiawei Shao55809702019-07-17 00:00:10 +0000309 return MTLPixelFormatBC7_RGBAUnorm_sRGB;
Loko Kungc7226a72021-08-31 00:15:45 +0000310#else
Li Hao538d8d52022-01-05 01:31:16 +0000311 case wgpu::TextureFormat::Depth24UnormStencil8:
312
Loko Kungc7226a72021-08-31 00:15:45 +0000313 case wgpu::TextureFormat::BC1RGBAUnorm:
314 case wgpu::TextureFormat::BC1RGBAUnormSrgb:
315 case wgpu::TextureFormat::BC2RGBAUnorm:
316 case wgpu::TextureFormat::BC2RGBAUnormSrgb:
317 case wgpu::TextureFormat::BC3RGBAUnorm:
318 case wgpu::TextureFormat::BC3RGBAUnormSrgb:
319 case wgpu::TextureFormat::BC4RSnorm:
320 case wgpu::TextureFormat::BC4RUnorm:
321 case wgpu::TextureFormat::BC5RGSnorm:
322 case wgpu::TextureFormat::BC5RGUnorm:
323 case wgpu::TextureFormat::BC6HRGBFloat:
324 case wgpu::TextureFormat::BC6HRGBUfloat:
325 case wgpu::TextureFormat::BC7RGBAUnorm:
326 case wgpu::TextureFormat::BC7RGBAUnormSrgb:
Corentin Wallezb629c502019-10-08 07:44:21 +0000327#endif
Jiawei Shaoea2d5582019-07-10 23:58:13 +0000328
Loko Kungc7226a72021-08-31 00:15:45 +0000329 case wgpu::TextureFormat::R8BG8Biplanar420Unorm:
330
331 case wgpu::TextureFormat::ETC2RGB8Unorm:
332 case wgpu::TextureFormat::ETC2RGB8UnormSrgb:
333 case wgpu::TextureFormat::ETC2RGB8A1Unorm:
334 case wgpu::TextureFormat::ETC2RGB8A1UnormSrgb:
335 case wgpu::TextureFormat::ETC2RGBA8Unorm:
336 case wgpu::TextureFormat::ETC2RGBA8UnormSrgb:
337 case wgpu::TextureFormat::EACR11Unorm:
338 case wgpu::TextureFormat::EACR11Snorm:
339 case wgpu::TextureFormat::EACRG11Unorm:
340 case wgpu::TextureFormat::EACRG11Snorm:
341
Loko Kung37a86492021-09-07 18:39:04 +0000342 case wgpu::TextureFormat::ASTC4x4Unorm:
343 case wgpu::TextureFormat::ASTC4x4UnormSrgb:
344 case wgpu::TextureFormat::ASTC5x4Unorm:
345 case wgpu::TextureFormat::ASTC5x4UnormSrgb:
346 case wgpu::TextureFormat::ASTC5x5Unorm:
347 case wgpu::TextureFormat::ASTC5x5UnormSrgb:
348 case wgpu::TextureFormat::ASTC6x5Unorm:
349 case wgpu::TextureFormat::ASTC6x5UnormSrgb:
350 case wgpu::TextureFormat::ASTC6x6Unorm:
351 case wgpu::TextureFormat::ASTC6x6UnormSrgb:
352 case wgpu::TextureFormat::ASTC8x5Unorm:
353 case wgpu::TextureFormat::ASTC8x5UnormSrgb:
354 case wgpu::TextureFormat::ASTC8x6Unorm:
355 case wgpu::TextureFormat::ASTC8x6UnormSrgb:
356 case wgpu::TextureFormat::ASTC8x8Unorm:
357 case wgpu::TextureFormat::ASTC8x8UnormSrgb:
358 case wgpu::TextureFormat::ASTC10x5Unorm:
359 case wgpu::TextureFormat::ASTC10x5UnormSrgb:
360 case wgpu::TextureFormat::ASTC10x6Unorm:
361 case wgpu::TextureFormat::ASTC10x6UnormSrgb:
362 case wgpu::TextureFormat::ASTC10x8Unorm:
363 case wgpu::TextureFormat::ASTC10x8UnormSrgb:
364 case wgpu::TextureFormat::ASTC10x10Unorm:
365 case wgpu::TextureFormat::ASTC10x10UnormSrgb:
366 case wgpu::TextureFormat::ASTC12x10Unorm:
367 case wgpu::TextureFormat::ASTC12x10UnormSrgb:
368 case wgpu::TextureFormat::ASTC12x12Unorm:
369 case wgpu::TextureFormat::ASTC12x12UnormSrgb:
370
Kai Ninomiyafa9ca442021-09-17 18:25:53 +0000371 // TODO(dawn:666): implement stencil8
Loko Kungc7226a72021-08-31 00:15:45 +0000372 case wgpu::TextureFormat::Stencil8:
373 case wgpu::TextureFormat::Undefined:
Jiawei Shaoc2750ab2019-06-01 02:30:51 +0000374 UNREACHABLE();
Corentin Wallez0cdf9e02019-03-01 12:01:18 +0000375 }
376 }
377
378 MaybeError ValidateIOSurfaceCanBeWrapped(const DeviceBase*,
379 const TextureDescriptor* descriptor,
380 IOSurfaceRef ioSurface,
381 uint32_t plane) {
382 // IOSurfaceGetPlaneCount can return 0 for non-planar IOSurfaces but we will treat
383 // non-planar like it is a single plane.
384 size_t surfacePlaneCount = std::max(size_t(1), IOSurfaceGetPlaneCount(ioSurface));
Brandon Joneseb0d9002021-10-22 17:39:20 +0000385 DAWN_INVALID_IF(plane >= surfacePlaneCount,
386 "IOSurface plane (%u) exceeds the surface's plane count (%u).", plane,
387 surfacePlaneCount);
Corentin Wallez0cdf9e02019-03-01 12:01:18 +0000388
Brandon Joneseb0d9002021-10-22 17:39:20 +0000389 DAWN_INVALID_IF(descriptor->dimension != wgpu::TextureDimension::e2D,
390 "Texture dimension (%s) is not %s.", descriptor->dimension,
391 wgpu::TextureDimension::e2D);
Corentin Wallez0cdf9e02019-03-01 12:01:18 +0000392
Brandon Joneseb0d9002021-10-22 17:39:20 +0000393 DAWN_INVALID_IF(descriptor->mipLevelCount != 1, "Mip level count (%u) is not 1.",
394 descriptor->mipLevelCount);
Corentin Wallez0cdf9e02019-03-01 12:01:18 +0000395
Brandon Joneseb0d9002021-10-22 17:39:20 +0000396 DAWN_INVALID_IF(descriptor->size.depthOrArrayLayers != 1,
397 "Array layer count (%u) is not 1.", descriptor->size.depthOrArrayLayers);
Corentin Wallez0cdf9e02019-03-01 12:01:18 +0000398
Brandon Joneseb0d9002021-10-22 17:39:20 +0000399 DAWN_INVALID_IF(descriptor->sampleCount != 1, "Sample count (%u) is not 1.",
400 descriptor->sampleCount);
Corentin Wallez0cdf9e02019-03-01 12:01:18 +0000401
Brandon Joneseb0d9002021-10-22 17:39:20 +0000402 uint32_t surfaceWidth = IOSurfaceGetWidthOfPlane(ioSurface, plane);
403 uint32_t surfaceHeight = IOSurfaceGetHeightOfPlane(ioSurface, plane);
404
405 DAWN_INVALID_IF(
406 descriptor->size.width != surfaceWidth || descriptor->size.height != surfaceHeight ||
407 descriptor->size.depthOrArrayLayers != 1,
408 "IOSurface size (width: %u, height %u, depth: 1) doesn't match descriptor size %s.",
409 surfaceWidth, surfaceHeight, &descriptor->size);
Corentin Wallez0cdf9e02019-03-01 12:01:18 +0000410
Corentin Wallez1f6c8c42019-10-23 11:57:41 +0000411 wgpu::TextureFormat ioSurfaceFormat;
Corentin Wallez0cdf9e02019-03-01 12:01:18 +0000412 DAWN_TRY_ASSIGN(ioSurfaceFormat,
413 GetFormatEquivalentToIOSurfaceFormat(IOSurfaceGetPixelFormat(ioSurface)));
Brandon Joneseb0d9002021-10-22 17:39:20 +0000414 DAWN_INVALID_IF(descriptor->format != ioSurfaceFormat,
415 "IOSurface format (%s) doesn't match the descriptor format (%s).",
416 ioSurfaceFormat, descriptor->format);
Corentin Wallez0cdf9e02019-03-01 12:01:18 +0000417
418 return {};
419 }
420
Austin Eng0eff5982021-07-27 19:59:58 +0000421 NSRef<MTLTextureDescriptor> Texture::CreateMetalTextureDescriptor() const {
Corentin Wallez0055d952020-11-16 23:07:56 +0000422 NSRef<MTLTextureDescriptor> mtlDescRef = AcquireNSRef([MTLTextureDescriptor new]);
423 MTLTextureDescriptor* mtlDesc = mtlDescRef.Get();
Corentin Wallez0cdf9e02019-03-01 12:01:18 +0000424
Austin Eng0eff5982021-07-27 19:59:58 +0000425 mtlDesc.width = GetWidth();
426 mtlDesc.height = GetHeight();
427 mtlDesc.sampleCount = GetSampleCount();
Yancf0e4fc2022-01-06 09:01:58 +0000428 // Metal only allows format reinterpretation to happen on swizzle pattern or conversion
429 // between linear space and sRGB. For example, creating bgra8Unorm texture view on
430 // rgba8Unorm texture or creating rgba8Unorm_srgb texture view on rgab8Unorm texture.
431 // TODO: add MTLTextureUsagePixelFormatView when needed when we support other format
Corentin Wallezcaec4ab2020-08-18 15:39:06 +0000432 // reinterpretation.
Austin Eng0eff5982021-07-27 19:59:58 +0000433 mtlDesc.usage = MetalTextureUsage(GetFormat(), GetInternalUsage(), GetSampleCount());
434 mtlDesc.pixelFormat = MetalPixelFormat(GetFormat().format);
435 mtlDesc.mipmapLevelCount = GetNumMipLevels();
Corentin Wallez0cdf9e02019-03-01 12:01:18 +0000436 mtlDesc.storageMode = MTLStorageModePrivate;
437
Corentin Wallez8a5325c2020-06-15 09:57:51 +0000438 // Choose the correct MTLTextureType and paper over differences in how the array layer count
439 // is specified.
Austin Eng0eff5982021-07-27 19:59:58 +0000440 switch (GetDimension()) {
Corentin Wallez8a5325c2020-06-15 09:57:51 +0000441 case wgpu::TextureDimension::e2D:
Austin Eng0eff5982021-07-27 19:59:58 +0000442 mtlDesc.depth = 1;
443 mtlDesc.arrayLength = GetArrayLayers();
444 if (mtlDesc.arrayLength > 1) {
Corentin Wallez8a5325c2020-06-15 09:57:51 +0000445 ASSERT(mtlDesc.sampleCount == 1);
446 mtlDesc.textureType = MTLTextureType2DArray;
Austin Eng0eff5982021-07-27 19:59:58 +0000447 } else if (mtlDesc.sampleCount > 1) {
448 mtlDesc.textureType = MTLTextureType2DMultisample;
Corentin Wallez8a5325c2020-06-15 09:57:51 +0000449 } else {
Austin Eng0eff5982021-07-27 19:59:58 +0000450 mtlDesc.textureType = MTLTextureType2D;
Corentin Wallez8a5325c2020-06-15 09:57:51 +0000451 }
452 break;
Yunchao He1b9bcfc2021-02-03 16:36:59 +0000453 case wgpu::TextureDimension::e3D:
Austin Eng0eff5982021-07-27 19:59:58 +0000454 mtlDesc.depth = GetDepth();
455 mtlDesc.arrayLength = 1;
Yunchao He1b9bcfc2021-02-03 16:36:59 +0000456 ASSERT(mtlDesc.sampleCount == 1);
457 mtlDesc.textureType = MTLTextureType3D;
458 break;
Corentin Wallez8a5325c2020-06-15 09:57:51 +0000459
Corentin Wallezeec9edf2020-09-24 14:56:50 +0000460 case wgpu::TextureDimension::e1D:
Corentin Wallez8a5325c2020-06-15 09:57:51 +0000461 UNREACHABLE();
462 }
Jiawei Shao865cad82019-04-09 08:04:59 +0000463
Corentin Wallez0055d952020-11-16 23:07:56 +0000464 return mtlDescRef;
Corentin Wallez0ba55502017-06-14 15:46:59 -0400465 }
466
Corentin Wallez50f99582021-03-31 18:36:32 +0000467 // static
468 ResultOrError<Ref<Texture>> Texture::Create(Device* device,
469 const TextureDescriptor* descriptor) {
Corentin Wallez03f94372021-07-21 09:34:28 +0000470 Ref<Texture> texture =
471 AcquireRef(new Texture(device, descriptor, TextureState::OwnedInternal));
472 DAWN_TRY(texture->InitializeAsInternalTexture(descriptor));
473 return texture;
Corentin Wallez50f99582021-03-31 18:36:32 +0000474 }
475
Corentin Wallez03f94372021-07-21 09:34:28 +0000476 // static
477 ResultOrError<Ref<Texture>> Texture::CreateFromIOSurface(
478 Device* device,
479 const ExternalImageDescriptor* descriptor,
480 IOSurfaceRef ioSurface,
481 uint32_t plane) {
Corentin Wallezc6d3a842021-12-03 16:47:18 +0000482 const TextureDescriptor* textureDescriptor = FromAPI(descriptor->cTextureDescriptor);
Corentin Wallez03f94372021-07-21 09:34:28 +0000483
484 Ref<Texture> texture =
485 AcquireRef(new Texture(device, textureDescriptor, TextureState::OwnedInternal));
486 DAWN_TRY(texture->InitializeFromIOSurface(descriptor, textureDescriptor, ioSurface, plane));
487 return texture;
488 }
489
490 // static
491 Ref<Texture> Texture::CreateWrapping(Device* device,
492 const TextureDescriptor* descriptor,
493 NSPRef<id<MTLTexture>> wrapped) {
494 Ref<Texture> texture =
495 AcquireRef(new Texture(device, descriptor, TextureState::OwnedInternal));
496 texture->InitializeAsWrapping(descriptor, std::move(wrapped));
497 return texture;
498 }
499
500 MaybeError Texture::InitializeAsInternalTexture(const TextureDescriptor* descriptor) {
501 Device* device = ToBackend(GetDevice());
502
Austin Eng0eff5982021-07-27 19:59:58 +0000503 NSRef<MTLTextureDescriptor> mtlDesc = CreateMetalTextureDescriptor();
Corentin Wallez03f94372021-07-21 09:34:28 +0000504 mMtlUsage = [*mtlDesc usage];
Corentin Wallez0055d952020-11-16 23:07:56 +0000505 mMtlTexture =
506 AcquireNSPRef([device->GetMTLDevice() newTextureWithDescriptor:mtlDesc.Get()]);
Corentin Wallez03f94372021-07-21 09:34:28 +0000507
508 if (mMtlTexture == nil) {
509 return DAWN_OUT_OF_MEMORY_ERROR("Failed to allocate texture.");
510 }
Austin Eng0d661982020-01-16 00:12:10 +0000511
512 if (device->IsToggleEnabled(Toggle::NonzeroClearResourcesOnCreationForTesting)) {
Corentin Wallez03f94372021-07-21 09:34:28 +0000513 DAWN_TRY(ClearTexture(device->GetPendingCommandContext(), GetAllSubresources(),
514 TextureBase::ClearValue::NonZero));
Austin Eng0d661982020-01-16 00:12:10 +0000515 }
Corentin Wallez03f94372021-07-21 09:34:28 +0000516
517 return {};
Corentin Wallez0ba55502017-06-14 15:46:59 -0400518 }
519
Corentin Wallez03f94372021-07-21 09:34:28 +0000520 void Texture::InitializeAsWrapping(const TextureDescriptor* descriptor,
521 NSPRef<id<MTLTexture>> wrapped) {
Austin Eng0eff5982021-07-27 19:59:58 +0000522 NSRef<MTLTextureDescriptor> mtlDesc = CreateMetalTextureDescriptor();
Austin Eng75c50672021-06-24 02:01:46 +0000523 mMtlUsage = [*mtlDesc usage];
Corentin Wallez03f94372021-07-21 09:34:28 +0000524 mMtlTexture = std::move(wrapped);
Kai Ninomiya35bf4242017-07-19 15:41:17 -0700525 }
526
Corentin Wallez03f94372021-07-21 09:34:28 +0000527 MaybeError Texture::InitializeFromIOSurface(const ExternalImageDescriptor* descriptor,
528 const TextureDescriptor* textureDescriptor,
529 IOSurfaceRef ioSurface,
530 uint32_t plane) {
531 Device* device = ToBackend(GetDevice());
532
Austin Eng0eff5982021-07-27 19:59:58 +0000533 NSRef<MTLTextureDescriptor> mtlDesc = CreateMetalTextureDescriptor();
Corentin Wallez0055d952020-11-16 23:07:56 +0000534 [*mtlDesc setStorageMode:kIOSurfaceStorageMode];
535
Corentin Wallez03f94372021-07-21 09:34:28 +0000536 mMtlUsage = [*mtlDesc usage];
Corentin Wallez0055d952020-11-16 23:07:56 +0000537 mMtlTexture = AcquireNSPRef([device->GetMTLDevice() newTextureWithDescriptor:mtlDesc.Get()
538 iosurface:ioSurface
539 plane:plane]);
Austin Eng0d661982020-01-16 00:12:10 +0000540
Austin Eng0b297322020-09-22 20:10:46 +0000541 SetIsSubresourceContentInitialized(descriptor->isInitialized, GetAllSubresources());
Corentin Wallez03f94372021-07-21 09:34:28 +0000542
543 return {};
Corentin Wallez0cdf9e02019-03-01 12:01:18 +0000544 }
545
Corentin Wallez0ba55502017-06-14 15:46:59 -0400546 Texture::~Texture() {
Natasha Leecae68ff2019-03-27 22:04:10 +0000547 }
548
Loko Kunge9c84c02021-11-11 01:39:52 +0000549 void Texture::DestroyImpl() {
Loko Kung6331f952021-12-01 18:54:40 +0000550 TextureBase::DestroyImpl();
Corentin Wallez0055d952020-11-16 23:07:56 +0000551 mMtlTexture = nullptr;
Corentin Wallez0ba55502017-06-14 15:46:59 -0400552 }
553
554 id<MTLTexture> Texture::GetMTLTexture() {
Corentin Wallez0055d952020-11-16 23:07:56 +0000555 return mMtlTexture.Get();
Corentin Wallez0ba55502017-06-14 15:46:59 -0400556 }
557
Yancf0e4fc2022-01-06 09:01:58 +0000558 NSPRef<id<MTLTexture>> Texture::CreateFormatView(wgpu::TextureFormat format) {
559 if (GetFormat().format == format) {
560 return mMtlTexture;
561 }
562
563 ASSERT(AllowFormatReinterpretationWithoutFlag(MetalPixelFormat(GetFormat().format),
564 MetalPixelFormat(format)));
565 return AcquireNSPRef(
566 [mMtlTexture.Get() newTextureViewWithPixelFormat:MetalPixelFormat(format)]);
567 }
568
Austin Eng26468c42021-05-08 16:01:16 +0000569 MaybeError Texture::ClearTexture(CommandRecordingContext* commandContext,
570 const SubresourceRange& range,
Austin Eng0d661982020-01-16 00:12:10 +0000571 TextureBase::ClearValue clearValue) {
572 Device* device = ToBackend(GetDevice());
573
Austin Eng0d661982020-01-16 00:12:10 +0000574 const uint8_t clearColor = (clearValue == TextureBase::ClearValue::Zero) ? 0 : 1;
575 const double dClearColor = (clearValue == TextureBase::ClearValue::Zero) ? 0.0 : 1.0;
576
Austin Eng75c50672021-06-24 02:01:46 +0000577 if ((mMtlUsage & MTLTextureUsageRenderTarget) != 0) {
Austin Eng0d661982020-01-16 00:12:10 +0000578 ASSERT(GetFormat().isRenderable);
579
580 // End the blit encoder if it is open.
581 commandContext->EndBlit();
582
583 if (GetFormat().HasDepthOrStencil()) {
584 // Create a render pass to clear each subresource.
Yunchao He5fafb492020-06-12 00:37:31 +0000585 for (uint32_t level = range.baseMipLevel;
586 level < range.baseMipLevel + range.levelCount; ++level) {
587 for (uint32_t arrayLayer = range.baseArrayLayer;
588 arrayLayer < range.baseArrayLayer + range.layerCount; arrayLayer++) {
Austin Eng0d661982020-01-16 00:12:10 +0000589 if (clearValue == TextureBase::ClearValue::Zero &&
Austin Eng2cf5a082020-08-06 17:00:29 +0000590 IsSubresourceContentInitialized(SubresourceRange::SingleMipAndLayer(
591 level, arrayLayer, range.aspects))) {
Austin Eng0d661982020-01-16 00:12:10 +0000592 // Skip lazy clears if already initialized.
593 continue;
594 }
595
Corentin Wallez0055d952020-11-16 23:07:56 +0000596 // Note that this creates a descriptor that's autoreleased so we don't use
597 // AcquireNSRef
598 NSRef<MTLRenderPassDescriptor> descriptorRef =
Austin Eng0d661982020-01-16 00:12:10 +0000599 [MTLRenderPassDescriptor renderPassDescriptor];
Corentin Wallez0055d952020-11-16 23:07:56 +0000600 MTLRenderPassDescriptor* descriptor = descriptorRef.Get();
Austin Eng0d661982020-01-16 00:12:10 +0000601
Austin Eng2cf5a082020-08-06 17:00:29 +0000602 // At least one aspect needs clearing. Iterate the aspects individually to
603 // determine which to clear.
604 for (Aspect aspect : IterateEnumMask(range.aspects)) {
605 if (clearValue == TextureBase::ClearValue::Zero &&
606 IsSubresourceContentInitialized(SubresourceRange::SingleMipAndLayer(
607 level, arrayLayer, aspect))) {
608 // Skip lazy clears if already initialized.
609 continue;
610 }
611
Austin Engfd783ce2021-05-18 21:51:33 +0000612 ASSERT(GetDimension() == wgpu::TextureDimension::e2D);
Austin Eng2cf5a082020-08-06 17:00:29 +0000613 switch (aspect) {
614 case Aspect::Depth:
615 descriptor.depthAttachment.texture = GetMTLTexture();
Austin Eng600f6f52020-12-03 16:55:53 +0000616 descriptor.depthAttachment.level = level;
617 descriptor.depthAttachment.slice = arrayLayer;
Austin Eng2cf5a082020-08-06 17:00:29 +0000618 descriptor.depthAttachment.loadAction = MTLLoadActionClear;
619 descriptor.depthAttachment.storeAction = MTLStoreActionStore;
620 descriptor.depthAttachment.clearDepth = dClearColor;
621 break;
622 case Aspect::Stencil:
623 descriptor.stencilAttachment.texture = GetMTLTexture();
Austin Eng600f6f52020-12-03 16:55:53 +0000624 descriptor.stencilAttachment.level = level;
625 descriptor.stencilAttachment.slice = arrayLayer;
Austin Eng2cf5a082020-08-06 17:00:29 +0000626 descriptor.stencilAttachment.loadAction = MTLLoadActionClear;
627 descriptor.stencilAttachment.storeAction = MTLStoreActionStore;
628 descriptor.stencilAttachment.clearStencil =
629 static_cast<uint32_t>(clearColor);
630 break;
631 default:
632 UNREACHABLE();
Austin Eng2cf5a082020-08-06 17:00:29 +0000633 }
Austin Eng0d661982020-01-16 00:12:10 +0000634 }
635
636 commandContext->BeginRender(descriptor);
637 commandContext->EndRender();
638 }
639 }
640 } else {
641 ASSERT(GetFormat().IsColor());
Yunchao He5fafb492020-06-12 00:37:31 +0000642 for (uint32_t level = range.baseMipLevel;
643 level < range.baseMipLevel + range.levelCount; ++level) {
Corentin Wallezda6dccd2020-05-29 07:37:48 +0000644 // Create multiple render passes with each subresource as a color attachment to
645 // clear them all. Only do this for array layers to ensure all attachments have
646 // the same size.
Corentin Wallez0055d952020-11-16 23:07:56 +0000647 NSRef<MTLRenderPassDescriptor> descriptor;
Corentin Wallezda6dccd2020-05-29 07:37:48 +0000648 uint32_t attachment = 0;
649
Austin Engfd783ce2021-05-18 21:51:33 +0000650 uint32_t numZSlices = GetMipLevelVirtualSize(level).depthOrArrayLayers;
651
Yunchao He5fafb492020-06-12 00:37:31 +0000652 for (uint32_t arrayLayer = range.baseArrayLayer;
653 arrayLayer < range.baseArrayLayer + range.layerCount; arrayLayer++) {
Austin Eng0d661982020-01-16 00:12:10 +0000654 if (clearValue == TextureBase::ClearValue::Zero &&
Austin Eng2cf5a082020-08-06 17:00:29 +0000655 IsSubresourceContentInitialized(SubresourceRange::SingleMipAndLayer(
656 level, arrayLayer, Aspect::Color))) {
Austin Eng0d661982020-01-16 00:12:10 +0000657 // Skip lazy clears if already initialized.
658 continue;
659 }
660
Austin Engfd783ce2021-05-18 21:51:33 +0000661 for (uint32_t z = 0; z < numZSlices; ++z) {
662 if (descriptor == nullptr) {
663 // Note that this creates a descriptor that's autoreleased so we
664 // don't use AcquireNSRef
665 descriptor = [MTLRenderPassDescriptor renderPassDescriptor];
666 }
Austin Eng0d661982020-01-16 00:12:10 +0000667
Austin Engfd783ce2021-05-18 21:51:33 +0000668 [*descriptor colorAttachments][attachment].texture = GetMTLTexture();
669 [*descriptor colorAttachments][attachment].loadAction =
670 MTLLoadActionClear;
671 [*descriptor colorAttachments][attachment].storeAction =
672 MTLStoreActionStore;
673 [*descriptor colorAttachments][attachment].clearColor =
674 MTLClearColorMake(dClearColor, dClearColor, dClearColor,
675 dClearColor);
676 [*descriptor colorAttachments][attachment].level = level;
677 [*descriptor colorAttachments][attachment].slice = arrayLayer;
678 [*descriptor colorAttachments][attachment].depthPlane = z;
Austin Eng0d661982020-01-16 00:12:10 +0000679
Austin Engfd783ce2021-05-18 21:51:33 +0000680 attachment++;
Austin Eng0d661982020-01-16 00:12:10 +0000681
Austin Engfd783ce2021-05-18 21:51:33 +0000682 if (attachment == kMaxColorAttachments) {
683 attachment = 0;
684 commandContext->BeginRender(descriptor.Get());
685 commandContext->EndRender();
686 descriptor = nullptr;
687 }
Austin Eng0d661982020-01-16 00:12:10 +0000688 }
689 }
Austin Eng0d661982020-01-16 00:12:10 +0000690
Corentin Wallez0055d952020-11-16 23:07:56 +0000691 if (descriptor != nullptr) {
692 commandContext->BeginRender(descriptor.Get());
Corentin Wallezda6dccd2020-05-29 07:37:48 +0000693 commandContext->EndRender();
694 }
Austin Eng0d661982020-01-16 00:12:10 +0000695 }
696 }
697 } else {
Yunchao He5fafb492020-06-12 00:37:31 +0000698 Extent3D largestMipSize = GetMipLevelVirtualSize(range.baseMipLevel);
Austin Eng0d661982020-01-16 00:12:10 +0000699
700 // Encode a buffer to texture copy to clear each subresource.
Austin Eng2cf5a082020-08-06 17:00:29 +0000701 for (Aspect aspect : IterateEnumMask(range.aspects)) {
Austin Eng3cd8c432021-06-01 21:25:33 +0000702 // Compute the buffer size big enough to fill the largest mip.
703 const TexelBlockInfo& blockInfo = GetFormat().GetAspectInfo(aspect).block;
704
705 // Metal validation layers: sourceBytesPerRow must be at least 64.
706 uint32_t largestMipBytesPerRow =
707 std::max((largestMipSize.width / blockInfo.width) * blockInfo.byteSize, 64u);
708
709 // Metal validation layers: sourceBytesPerImage must be at least 512.
710 uint64_t largestMipBytesPerImage =
711 std::max(static_cast<uint64_t>(largestMipBytesPerRow) *
712 (largestMipSize.height / blockInfo.height),
713 512llu);
714
715 uint64_t bufferSize = largestMipBytesPerImage * largestMipSize.depthOrArrayLayers;
716
717 if (bufferSize > std::numeric_limits<NSUInteger>::max()) {
718 return DAWN_OUT_OF_MEMORY_ERROR("Unable to allocate buffer.");
719 }
720
721 DynamicUploader* uploader = device->GetDynamicUploader();
722 UploadHandle uploadHandle;
723 DAWN_TRY_ASSIGN(uploadHandle,
724 uploader->Allocate(bufferSize, device->GetPendingCommandSerial(),
725 blockInfo.byteSize));
726 memset(uploadHandle.mappedBuffer, clearColor, bufferSize);
727
728 id<MTLBuffer> uploadBuffer =
729 ToBackend(uploadHandle.stagingBuffer)->GetBufferHandle();
730
Austin Eng2cf5a082020-08-06 17:00:29 +0000731 for (uint32_t level = range.baseMipLevel;
732 level < range.baseMipLevel + range.levelCount; ++level) {
733 Extent3D virtualSize = GetMipLevelVirtualSize(level);
Austin Eng0d661982020-01-16 00:12:10 +0000734
Austin Eng2cf5a082020-08-06 17:00:29 +0000735 for (uint32_t arrayLayer = range.baseArrayLayer;
736 arrayLayer < range.baseArrayLayer + range.layerCount; ++arrayLayer) {
737 if (clearValue == TextureBase::ClearValue::Zero &&
738 IsSubresourceContentInitialized(
739 SubresourceRange::SingleMipAndLayer(level, arrayLayer, aspect))) {
740 // Skip lazy clears if already initialized.
741 continue;
742 }
Austin Eng0d661982020-01-16 00:12:10 +0000743
Austin Eng2cf5a082020-08-06 17:00:29 +0000744 MTLBlitOption blitOption = ComputeMTLBlitOption(GetFormat(), aspect);
Austin Eng3cd8c432021-06-01 21:25:33 +0000745 [commandContext->EnsureBlit()
746 copyFromBuffer:uploadBuffer
Austin Eng0d661982020-01-16 00:12:10 +0000747 sourceOffset:uploadHandle.startOffset
748 sourceBytesPerRow:largestMipBytesPerRow
749 sourceBytesPerImage:largestMipBytesPerImage
750 sourceSize:MTLSizeMake(virtualSize.width, virtualSize.height,
Austin Engfd783ce2021-05-18 21:51:33 +0000751 virtualSize.depthOrArrayLayers)
Austin Eng0d661982020-01-16 00:12:10 +0000752 toTexture:GetMTLTexture()
753 destinationSlice:arrayLayer
754 destinationLevel:level
755 destinationOrigin:MTLOriginMake(0, 0, 0)
Austin Eng2cf5a082020-08-06 17:00:29 +0000756 options:blitOption];
Austin Eng0d661982020-01-16 00:12:10 +0000757 }
758 }
759 }
760 }
761
762 if (clearValue == TextureBase::ClearValue::Zero) {
Yunchao He5fafb492020-06-12 00:37:31 +0000763 SetIsSubresourceContentInitialized(true, range);
Austin Eng0d661982020-01-16 00:12:10 +0000764 device->IncrementLazyClearCountForTesting();
765 }
766 return {};
767 }
768
Austin Eng26468c42021-05-08 16:01:16 +0000769 void Texture::EnsureSubresourceContentInitialized(CommandRecordingContext* commandContext,
770 const SubresourceRange& range) {
Austin Eng0d661982020-01-16 00:12:10 +0000771 if (!GetDevice()->IsToggleEnabled(Toggle::LazyClearResourceOnFirstUse)) {
772 return;
773 }
Yunchao He5fafb492020-06-12 00:37:31 +0000774 if (!IsSubresourceContentInitialized(range)) {
Austin Eng0d661982020-01-16 00:12:10 +0000775 // If subresource has not been initialized, clear it to black as it could
776 // contain dirty bits from recycled memory
Austin Eng26468c42021-05-08 16:01:16 +0000777 GetDevice()->ConsumedError(
778 ClearTexture(commandContext, range, TextureBase::ClearValue::Zero));
Austin Eng0d661982020-01-16 00:12:10 +0000779 }
780 }
781
Corentin Wallez50f99582021-03-31 18:36:32 +0000782 // static
783 ResultOrError<Ref<TextureView>> TextureView::Create(TextureBase* texture,
784 const TextureViewDescriptor* descriptor) {
Corentin Wallez03f94372021-07-21 09:34:28 +0000785 Ref<TextureView> view = AcquireRef(new TextureView(texture, descriptor));
786 DAWN_TRY(view->Initialize(descriptor));
787 return view;
Corentin Wallez50f99582021-03-31 18:36:32 +0000788 }
789
Corentin Wallez03f94372021-07-21 09:34:28 +0000790 MaybeError TextureView::Initialize(const TextureViewDescriptor* descriptor) {
791 Texture* texture = ToBackend(GetTexture());
Austin Engda3c5ef2021-07-29 21:49:47 +0000792
793 // Texture could be destroyed by the time we make a view.
794 if (GetTexture()->GetTextureState() == Texture::TextureState::Destroyed) {
795 return {};
796 }
797
Corentin Wallez03f94372021-07-21 09:34:28 +0000798 id<MTLTexture> mtlTexture = texture->GetMTLTexture();
Jiawei Shao5dee56f2018-12-29 10:47:28 +0000799
Austin Eng0eff5982021-07-27 19:59:58 +0000800 if (!UsageNeedsTextureView(texture->GetInternalUsage())) {
Corentin Wallez0055d952020-11-16 23:07:56 +0000801 mMtlTextureView = nullptr;
Jiawei Shao5dee56f2018-12-29 10:47:28 +0000802 } else if (!RequiresCreatingNewTextureView(texture, descriptor)) {
Corentin Wallez0055d952020-11-16 23:07:56 +0000803 mMtlTextureView = mtlTexture;
Jiawei Shao5dee56f2018-12-29 10:47:28 +0000804 } else {
805 MTLPixelFormat format = MetalPixelFormat(descriptor->format);
Austin Enga0f17252020-11-04 15:27:11 +0000806 if (descriptor->aspect == wgpu::TextureAspect::StencilOnly) {
807 if (@available(macOS 10.12, iOS 10.0, *)) {
Li Hao538d8d52022-01-05 01:31:16 +0000808 if (format == MTLPixelFormatDepth32Float_Stencil8) {
809 format = MTLPixelFormatX32_Stencil8;
810 }
811#if defined(DAWN_PLATFORM_MACOS)
812 else if (format == MTLPixelFormatDepth24Unorm_Stencil8) {
813 format = MTLPixelFormatX24_Stencil8;
814 }
815#endif
816 else {
817 UNREACHABLE();
818 }
Austin Enga0f17252020-11-04 15:27:11 +0000819 } else {
820 // TODO(enga): Add a workaround to back combined depth/stencil textures
821 // with Sampled usage using two separate textures.
822 // Or, consider always using the workaround for D32S8.
823 GetDevice()->ConsumedError(
824 DAWN_DEVICE_LOST_ERROR("Cannot create stencil-only texture view of "
825 "combined depth/stencil format."));
826 }
827 }
828
Jiawei Shao865cad82019-04-09 08:04:59 +0000829 MTLTextureType textureViewType =
830 MetalTextureViewType(descriptor->dimension, texture->GetSampleCount());
Jiawei Shao20301662019-02-21 00:45:19 +0000831 auto mipLevelRange = NSMakeRange(descriptor->baseMipLevel, descriptor->mipLevelCount);
832 auto arrayLayerRange =
833 NSMakeRange(descriptor->baseArrayLayer, descriptor->arrayLayerCount);
Jiawei Shao5dee56f2018-12-29 10:47:28 +0000834
Corentin Wallez0055d952020-11-16 23:07:56 +0000835 mMtlTextureView =
836 AcquireNSPRef([mtlTexture newTextureViewWithPixelFormat:format
Jiawei Shao5dee56f2018-12-29 10:47:28 +0000837 textureType:textureViewType
838 levels:mipLevelRange
Corentin Wallez0055d952020-11-16 23:07:56 +0000839 slices:arrayLayerRange]);
Corentin Wallez03f94372021-07-21 09:34:28 +0000840 if (mMtlTextureView == nil) {
841 return DAWN_INTERNAL_ERROR("Failed to create MTLTexture view.");
842 }
Jiawei Shao5dee56f2018-12-29 10:47:28 +0000843 }
Corentin Wallez03f94372021-07-21 09:34:28 +0000844
845 return {};
Corentin Wallez0ba55502017-06-14 15:46:59 -0400846 }
Corentin Wallezf58d84d2017-11-24 14:12:44 -0500847
Jiawei Shaoe8d12b42018-10-26 06:29:38 +0000848 id<MTLTexture> TextureView::GetMTLTexture() {
Corentin Wallez0055d952020-11-16 23:07:56 +0000849 ASSERT(mMtlTextureView != nullptr);
850 return mMtlTextureView.Get();
Jiawei Shaoe8d12b42018-10-26 06:29:38 +0000851 }
Corentin Wallez49a65d02018-07-24 16:45:45 +0200852}} // namespace dawn_native::metal