1 // Copyright 2021 The Dawn Authors 2 // 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 15 #include "tests/unittests/validation/ValidationTest.h" 16 17 #include "utils/WGPUHelpers.h" 18 19 namespace { 20 21 class VideoViewsValidation : public ValidationTest { 22 protected: CreateTestDevice()23 WGPUDevice CreateTestDevice() override { 24 dawn_native::DawnDeviceDescriptor descriptor; 25 descriptor.requiredFeatures = {"multiplanar-formats"}; 26 return adapter.CreateDevice(&descriptor); 27 } 28 CreateVideoTextureForTest(wgpu::TextureFormat format,wgpu::TextureUsage usage)29 wgpu::Texture CreateVideoTextureForTest(wgpu::TextureFormat format, 30 wgpu::TextureUsage usage) { 31 wgpu::TextureDescriptor descriptor; 32 descriptor.dimension = wgpu::TextureDimension::e2D; 33 descriptor.size.width = 1; 34 descriptor.size.height = 1; 35 descriptor.format = format; 36 descriptor.usage = usage; 37 return device.CreateTexture(&descriptor); 38 } 39 }; 40 41 // Test texture views compatibility rules. TEST_F(VideoViewsValidation,CreateViewFails)42 TEST_F(VideoViewsValidation, CreateViewFails) { 43 wgpu::Texture videoTexture = CreateVideoTextureForTest( 44 wgpu::TextureFormat::R8BG8Biplanar420Unorm, wgpu::TextureUsage::None); 45 46 wgpu::TextureViewDescriptor viewDesc = {}; 47 48 // Correct plane index but incompatible view format. 49 viewDesc.format = wgpu::TextureFormat::R8Uint; 50 viewDesc.aspect = wgpu::TextureAspect::Plane0Only; 51 ASSERT_DEVICE_ERROR(videoTexture.CreateView(&viewDesc)); 52 53 // Compatible view format but wrong plane index. 54 viewDesc.format = wgpu::TextureFormat::R8Unorm; 55 viewDesc.aspect = wgpu::TextureAspect::Plane1Only; 56 ASSERT_DEVICE_ERROR(videoTexture.CreateView(&viewDesc)); 57 58 // Compatible view format but wrong aspect. 59 viewDesc.format = wgpu::TextureFormat::R8Unorm; 60 viewDesc.aspect = wgpu::TextureAspect::All; 61 ASSERT_DEVICE_ERROR(videoTexture.CreateView(&viewDesc)); 62 63 // Create a single plane texture. 64 wgpu::TextureDescriptor desc; 65 desc.format = wgpu::TextureFormat::RGBA8Unorm; 66 desc.dimension = wgpu::TextureDimension::e2D; 67 desc.usage = wgpu::TextureUsage::None; 68 desc.size = {1, 1, 1}; 69 70 wgpu::Texture texture = device.CreateTexture(&desc); 71 72 // Plane aspect specified with non-planar texture. 73 viewDesc.aspect = wgpu::TextureAspect::Plane0Only; 74 ASSERT_DEVICE_ERROR(texture.CreateView(&viewDesc)); 75 76 viewDesc.aspect = wgpu::TextureAspect::Plane1Only; 77 ASSERT_DEVICE_ERROR(texture.CreateView(&viewDesc)); 78 79 // Planar views with non-planar texture. 80 viewDesc.aspect = wgpu::TextureAspect::Plane0Only; 81 viewDesc.format = wgpu::TextureFormat::R8Unorm; 82 ASSERT_DEVICE_ERROR(texture.CreateView(&viewDesc)); 83 84 viewDesc.aspect = wgpu::TextureAspect::Plane1Only; 85 viewDesc.format = wgpu::TextureFormat::RG8Unorm; 86 ASSERT_DEVICE_ERROR(texture.CreateView(&viewDesc)); 87 } 88 89 // Test texture views compatibility rules. TEST_F(VideoViewsValidation,CreateViewSucceeds)90 TEST_F(VideoViewsValidation, CreateViewSucceeds) { 91 wgpu::Texture yuvTexture = CreateVideoTextureForTest( 92 wgpu::TextureFormat::R8BG8Biplanar420Unorm, wgpu::TextureUsage::None); 93 94 // Per plane view formats unspecified. 95 wgpu::TextureViewDescriptor planeViewDesc = {}; 96 planeViewDesc.aspect = wgpu::TextureAspect::Plane0Only; 97 wgpu::TextureView plane0View = yuvTexture.CreateView(&planeViewDesc); 98 99 planeViewDesc.aspect = wgpu::TextureAspect::Plane1Only; 100 wgpu::TextureView plane1View = yuvTexture.CreateView(&planeViewDesc); 101 102 ASSERT_NE(plane0View.Get(), nullptr); 103 ASSERT_NE(plane1View.Get(), nullptr); 104 105 // Per plane view formats specified. 106 planeViewDesc.aspect = wgpu::TextureAspect::Plane0Only; 107 planeViewDesc.format = wgpu::TextureFormat::R8Unorm; 108 plane0View = yuvTexture.CreateView(&planeViewDesc); 109 110 planeViewDesc.aspect = wgpu::TextureAspect::Plane1Only; 111 planeViewDesc.format = wgpu::TextureFormat::RG8Unorm; 112 plane1View = yuvTexture.CreateView(&planeViewDesc); 113 114 ASSERT_NE(plane0View.Get(), nullptr); 115 ASSERT_NE(plane1View.Get(), nullptr); 116 } 117 118 // Test copying from one multi-planar format into another fails. TEST_F(VideoViewsValidation,T2TCopyAllAspectsFails)119 TEST_F(VideoViewsValidation, T2TCopyAllAspectsFails) { 120 wgpu::Texture srcTexture = CreateVideoTextureForTest( 121 wgpu::TextureFormat::R8BG8Biplanar420Unorm, wgpu::TextureUsage::TextureBinding); 122 123 wgpu::Texture dstTexture = CreateVideoTextureForTest( 124 wgpu::TextureFormat::R8BG8Biplanar420Unorm, wgpu::TextureUsage::TextureBinding); 125 126 wgpu::ImageCopyTexture copySrc = utils::CreateImageCopyTexture(srcTexture, 0, {0, 0, 0}); 127 128 wgpu::ImageCopyTexture copyDst = utils::CreateImageCopyTexture(dstTexture, 0, {0, 0, 0}); 129 130 wgpu::Extent3D copySize = {1, 1, 1}; 131 132 wgpu::CommandEncoder encoder = device.CreateCommandEncoder(); 133 encoder.CopyTextureToTexture(©Src, ©Dst, ©Size); 134 ASSERT_DEVICE_ERROR(encoder.Finish()); 135 } 136 137 // Test copying from one multi-planar format into another per plane fails. TEST_F(VideoViewsValidation,T2TCopyPlaneAspectFails)138 TEST_F(VideoViewsValidation, T2TCopyPlaneAspectFails) { 139 wgpu::Texture srcTexture = CreateVideoTextureForTest( 140 wgpu::TextureFormat::R8BG8Biplanar420Unorm, wgpu::TextureUsage::TextureBinding); 141 142 wgpu::Texture dstTexture = CreateVideoTextureForTest( 143 wgpu::TextureFormat::R8BG8Biplanar420Unorm, wgpu::TextureUsage::TextureBinding); 144 145 wgpu::ImageCopyTexture copySrc = utils::CreateImageCopyTexture( 146 srcTexture, 0, {0, 0, 0}, wgpu::TextureAspect::Plane0Only); 147 148 wgpu::ImageCopyTexture copyDst = utils::CreateImageCopyTexture( 149 dstTexture, 0, {0, 0, 0}, wgpu::TextureAspect::Plane1Only); 150 151 wgpu::Extent3D copySize = {1, 1, 1}; 152 153 { 154 wgpu::CommandEncoder encoder = device.CreateCommandEncoder(); 155 encoder.CopyTextureToTexture(©Src, ©Dst, ©Size); 156 ASSERT_DEVICE_ERROR(encoder.Finish()); 157 } 158 159 copySrc = utils::CreateImageCopyTexture(srcTexture, 0, {0, 0, 0}, 160 wgpu::TextureAspect::Plane1Only); 161 162 { 163 wgpu::CommandEncoder encoder = device.CreateCommandEncoder(); 164 encoder.CopyTextureToTexture(©Src, ©Dst, ©Size); 165 ASSERT_DEVICE_ERROR(encoder.Finish()); 166 } 167 } 168 169 // Test copying from a multi-planar format to a buffer fails. TEST_F(VideoViewsValidation,T2BCopyAllAspectsFails)170 TEST_F(VideoViewsValidation, T2BCopyAllAspectsFails) { 171 wgpu::Texture srcTexture = CreateVideoTextureForTest( 172 wgpu::TextureFormat::R8BG8Biplanar420Unorm, wgpu::TextureUsage::TextureBinding); 173 174 wgpu::BufferDescriptor bufferDescriptor; 175 bufferDescriptor.size = 1; 176 bufferDescriptor.usage = wgpu::BufferUsage::CopyDst; 177 wgpu::Buffer dstBuffer = device.CreateBuffer(&bufferDescriptor); 178 179 wgpu::ImageCopyTexture copySrc = utils::CreateImageCopyTexture(srcTexture, 0, {0, 0, 0}); 180 181 wgpu::ImageCopyBuffer copyDst = utils::CreateImageCopyBuffer(dstBuffer, 0, 4); 182 183 wgpu::Extent3D copySize = {1, 1, 1}; 184 185 wgpu::CommandEncoder encoder = device.CreateCommandEncoder(); 186 encoder.CopyTextureToBuffer(©Src, ©Dst, ©Size); 187 ASSERT_DEVICE_ERROR(encoder.Finish()); 188 } 189 190 // Test copying from multi-planar format per plane to a buffer fails. TEST_F(VideoViewsValidation,T2BCopyPlaneAspectsFails)191 TEST_F(VideoViewsValidation, T2BCopyPlaneAspectsFails) { 192 wgpu::Texture srcTexture = CreateVideoTextureForTest( 193 wgpu::TextureFormat::R8BG8Biplanar420Unorm, wgpu::TextureUsage::TextureBinding); 194 195 wgpu::BufferDescriptor bufferDescriptor; 196 bufferDescriptor.size = 1; 197 bufferDescriptor.usage = wgpu::BufferUsage::CopyDst; 198 wgpu::Buffer dstBuffer = device.CreateBuffer(&bufferDescriptor); 199 200 wgpu::ImageCopyTexture copySrc = utils::CreateImageCopyTexture( 201 srcTexture, 0, {0, 0, 0}, wgpu::TextureAspect::Plane0Only); 202 203 wgpu::ImageCopyBuffer copyDst = utils::CreateImageCopyBuffer(dstBuffer, 0, 4); 204 205 wgpu::Extent3D copySize = {1, 1, 1}; 206 207 { 208 wgpu::CommandEncoder encoder = device.CreateCommandEncoder(); 209 encoder.CopyTextureToBuffer(©Src, ©Dst, ©Size); 210 ASSERT_DEVICE_ERROR(encoder.Finish()); 211 } 212 213 copySrc = utils::CreateImageCopyTexture(srcTexture, 0, {0, 0, 0}, 214 wgpu::TextureAspect::Plane1Only); 215 216 { 217 wgpu::CommandEncoder encoder = device.CreateCommandEncoder(); 218 encoder.CopyTextureToBuffer(©Src, ©Dst, ©Size); 219 ASSERT_DEVICE_ERROR(encoder.Finish()); 220 } 221 } 222 223 // Test copying from a buffer to a multi-planar format fails. TEST_F(VideoViewsValidation,B2TCopyAllAspectsFails)224 TEST_F(VideoViewsValidation, B2TCopyAllAspectsFails) { 225 std::vector<uint8_t> dummyData(4, 0); 226 227 wgpu::Buffer srcBuffer = utils::CreateBufferFromData( 228 device, dummyData.data(), dummyData.size(), wgpu::BufferUsage::CopySrc); 229 230 wgpu::Texture dstTexture = CreateVideoTextureForTest( 231 wgpu::TextureFormat::R8BG8Biplanar420Unorm, wgpu::TextureUsage::TextureBinding); 232 233 wgpu::ImageCopyBuffer copySrc = utils::CreateImageCopyBuffer(srcBuffer, 0, 12, 4); 234 235 wgpu::ImageCopyTexture copyDst = utils::CreateImageCopyTexture(dstTexture, 0, {0, 0, 0}); 236 237 wgpu::Extent3D copySize = {1, 1, 1}; 238 239 wgpu::CommandEncoder encoder = device.CreateCommandEncoder(); 240 encoder.CopyBufferToTexture(©Src, ©Dst, ©Size); 241 ASSERT_DEVICE_ERROR(encoder.Finish()); 242 } 243 244 // Test copying from a buffer to a multi-planar format per plane fails. TEST_F(VideoViewsValidation,B2TCopyPlaneAspectsFails)245 TEST_F(VideoViewsValidation, B2TCopyPlaneAspectsFails) { 246 std::vector<uint8_t> dummyData(4, 0); 247 248 wgpu::Buffer srcBuffer = utils::CreateBufferFromData( 249 device, dummyData.data(), dummyData.size(), wgpu::BufferUsage::CopySrc); 250 251 wgpu::Texture dstTexture = CreateVideoTextureForTest( 252 wgpu::TextureFormat::R8BG8Biplanar420Unorm, wgpu::TextureUsage::TextureBinding); 253 254 wgpu::ImageCopyBuffer copySrc = utils::CreateImageCopyBuffer(srcBuffer, 0, 12, 4); 255 256 wgpu::ImageCopyTexture copyDst = utils::CreateImageCopyTexture( 257 dstTexture, 0, {0, 0, 0}, wgpu::TextureAspect::Plane0Only); 258 259 wgpu::Extent3D copySize = {1, 1, 1}; 260 261 { 262 wgpu::CommandEncoder encoder = device.CreateCommandEncoder(); 263 encoder.CopyBufferToTexture(©Src, ©Dst, ©Size); 264 ASSERT_DEVICE_ERROR(encoder.Finish()); 265 } 266 267 copyDst = utils::CreateImageCopyTexture(dstTexture, 0, {0, 0, 0}, 268 wgpu::TextureAspect::Plane1Only); 269 270 { 271 wgpu::CommandEncoder encoder = device.CreateCommandEncoder(); 272 encoder.CopyBufferToTexture(©Src, ©Dst, ©Size); 273 ASSERT_DEVICE_ERROR(encoder.Finish()); 274 } 275 } 276 277 // Tests which multi-planar formats are allowed to be sampled. TEST_F(VideoViewsValidation,SamplingMultiPlanarTexture)278 TEST_F(VideoViewsValidation, SamplingMultiPlanarTexture) { 279 wgpu::BindGroupLayout layout = utils::MakeBindGroupLayout( 280 device, {{0, wgpu::ShaderStage::Fragment, wgpu::TextureSampleType::Float}}); 281 282 // R8BG8Biplanar420Unorm is allowed to be sampled, if plane 0 or plane 1 is selected. 283 wgpu::Texture texture = CreateVideoTextureForTest( 284 wgpu::TextureFormat::R8BG8Biplanar420Unorm, wgpu::TextureUsage::TextureBinding); 285 286 wgpu::TextureViewDescriptor desc = {}; 287 288 desc.aspect = wgpu::TextureAspect::Plane0Only; 289 utils::MakeBindGroup(device, layout, {{0, texture.CreateView(&desc)}}); 290 291 desc.aspect = wgpu::TextureAspect::Plane1Only; 292 utils::MakeBindGroup(device, layout, {{0, texture.CreateView(&desc)}}); 293 } 294 295 // Tests creating a texture with a multi-plane format. TEST_F(VideoViewsValidation,CreateTextureFails)296 TEST_F(VideoViewsValidation, CreateTextureFails) { 297 // multi-planar formats are NOT allowed to be renderable. 298 ASSERT_DEVICE_ERROR(CreateVideoTextureForTest(wgpu::TextureFormat::R8BG8Biplanar420Unorm, 299 wgpu::TextureUsage::RenderAttachment)); 300 } 301 302 // Tests writing into a multi-planar format fails. TEST_F(VideoViewsValidation,WriteTextureAllAspectsFails)303 TEST_F(VideoViewsValidation, WriteTextureAllAspectsFails) { 304 wgpu::Texture texture = CreateVideoTextureForTest( 305 wgpu::TextureFormat::R8BG8Biplanar420Unorm, wgpu::TextureUsage::TextureBinding); 306 307 wgpu::TextureDataLayout textureDataLayout = utils::CreateTextureDataLayout(0, 4, 4); 308 309 wgpu::ImageCopyTexture imageCopyTexture = 310 utils::CreateImageCopyTexture(texture, 0, {0, 0, 0}); 311 312 std::vector<uint8_t> dummyData(4, 0); 313 wgpu::Extent3D writeSize = {1, 1, 1}; 314 315 wgpu::Queue queue = device.GetQueue(); 316 317 ASSERT_DEVICE_ERROR(queue.WriteTexture(&imageCopyTexture, dummyData.data(), 318 dummyData.size(), &textureDataLayout, &writeSize)); 319 } 320 321 // Tests writing into a multi-planar format per plane fails. TEST_F(VideoViewsValidation,WriteTexturePlaneAspectsFails)322 TEST_F(VideoViewsValidation, WriteTexturePlaneAspectsFails) { 323 wgpu::Texture texture = CreateVideoTextureForTest( 324 wgpu::TextureFormat::R8BG8Biplanar420Unorm, wgpu::TextureUsage::TextureBinding); 325 326 wgpu::TextureDataLayout textureDataLayout = utils::CreateTextureDataLayout(0, 12, 4); 327 wgpu::ImageCopyTexture imageCopyTexture = 328 utils::CreateImageCopyTexture(texture, 0, {0, 0, 0}, wgpu::TextureAspect::Plane0Only); 329 330 std::vector<uint8_t> dummmyData(4, 0); 331 wgpu::Extent3D writeSize = {1, 1, 1}; 332 333 wgpu::Queue queue = device.GetQueue(); 334 335 ASSERT_DEVICE_ERROR(queue.WriteTexture(&imageCopyTexture, dummmyData.data(), 336 dummmyData.size(), &textureDataLayout, &writeSize)); 337 } 338 339 } // anonymous namespace 340