Coverage Report

Created: 2024-09-14 07:19

/src/skia/tools/gpu/vk/VkYcbcrSamplerHelper.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright 2020 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 "tools/gpu/vk/VkYcbcrSamplerHelper.h"
9
10
#if defined(SK_VULKAN)
11
12
#include "include/gpu/ganesh/GrDirectContext.h"
13
#include "include/gpu/ganesh/vk/GrVkBackendSurface.h"
14
#include "include/gpu/vk/VulkanTypes.h"
15
#include "src/gpu/ganesh/GrDirectContextPriv.h"
16
#include "src/gpu/ganesh/vk/GrVkGpu.h"
17
#include "src/gpu/ganesh/vk/GrVkUtil.h"
18
#include "src/gpu/vk/VulkanInterface.h"
19
20
#if defined(SK_GRAPHITE)
21
#include "include/gpu/GpuTypes.h"
22
#include "include/gpu/graphite/BackendTexture.h"
23
#include "include/gpu/graphite/Recorder.h"
24
#include "include/gpu/graphite/vk/VulkanGraphiteTypes.h"
25
#include "src/gpu/graphite/vk/VulkanGraphiteUtilsPriv.h"
26
#include "src/gpu/graphite/vk/VulkanSharedContext.h"
27
#endif
28
29
0
int VkYcbcrSamplerHelper::GetExpectedY(int x, int y, int width, int height) {
30
0
    return 16 + (x + y) * 219 / (width + height - 2);
31
0
}
32
33
0
std::pair<int, int> VkYcbcrSamplerHelper::GetExpectedUV(int x, int y, int width, int height) {
34
0
    return { 16 + x * 224 / (width - 1), 16 + y * 224 / (height - 1) };
35
0
}
36
37
namespace {
38
39
0
void populate_ycbcr_image_info(VkImageCreateInfo* outImageInfo, uint32_t width, uint32_t height) {
40
0
    outImageInfo->sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
41
0
    outImageInfo->pNext = nullptr;
42
0
    outImageInfo->flags = 0;
43
0
    outImageInfo->imageType = VK_IMAGE_TYPE_2D;
44
0
    outImageInfo->format = VK_FORMAT_G8_B8R8_2PLANE_420_UNORM;
45
0
    outImageInfo->extent = VkExtent3D{width, height, 1};
46
0
    outImageInfo->mipLevels = 1;
47
0
    outImageInfo->arrayLayers = 1;
48
0
    outImageInfo->samples = VK_SAMPLE_COUNT_1_BIT;
49
0
    outImageInfo->tiling = VK_IMAGE_TILING_LINEAR;
50
0
    outImageInfo->usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT |
51
0
                          VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
52
0
    outImageInfo->sharingMode = VK_SHARING_MODE_EXCLUSIVE;
53
0
    outImageInfo->queueFamilyIndexCount = 0;
54
0
    outImageInfo->pQueueFamilyIndices = nullptr;
55
0
    outImageInfo->initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
56
0
}
57
58
bool find_memory_type_index(const VkPhysicalDeviceMemoryProperties& phyDevMemProps,
59
                            const VkMemoryRequirements& memoryRequirements,
60
0
                            uint32_t* memoryTypeIndex) {
61
0
    for (uint32_t i = 0; i < phyDevMemProps.memoryTypeCount; ++i) {
62
0
        if (memoryRequirements.memoryTypeBits & (1 << i)) {
63
            // Map host-visible memory.
64
0
            if (phyDevMemProps.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) {
65
0
                *memoryTypeIndex = i;
66
0
                return true;
67
0
            }
68
0
        }
69
0
    }
70
0
    return false;
71
0
}
72
73
}
74
75
#ifdef SK_GRAPHITE
76
// TODO(b/339211930): When graphite and ganesh can share a macro for certain Vulkan driver calls,
77
// much more code can be shared between this method and createGrBackendTexture.
78
0
bool VkYcbcrSamplerHelper::createBackendTexture(uint32_t width, uint32_t height) {
79
    // Create YCbCr image.
80
0
    VkImageCreateInfo vkImageInfo;
81
0
    populate_ycbcr_image_info(&vkImageInfo, width, height);
82
0
    SkASSERT(fImage == VK_NULL_HANDLE);
83
84
0
    VkResult result;
85
0
    VULKAN_CALL_RESULT(fSharedCtxt, result, CreateImage(fSharedCtxt->device(),
86
0
                                                        &vkImageInfo,
87
0
                                                        /*pAllocator=*/nullptr,
88
0
                                                        &fImage));
89
0
    if (result != VK_SUCCESS) {
90
0
        return false;
91
0
    }
92
93
0
    VkMemoryRequirements requirements;
94
0
    VULKAN_CALL(fSharedCtxt->interface(), GetImageMemoryRequirements(fSharedCtxt->device(),
95
0
                                                                     fImage,
96
0
                                                                     &requirements));
97
0
    uint32_t memoryTypeIndex = 0;
98
0
    const VkPhysicalDeviceMemoryProperties& phyDevMemProps =
99
0
            fSharedCtxt->vulkanCaps().physicalDeviceMemoryProperties2().memoryProperties;
100
0
    if (!find_memory_type_index(phyDevMemProps, requirements, &memoryTypeIndex)) {
101
0
        return false;
102
0
    }
103
104
0
    VkMemoryAllocateInfo allocInfo;
105
0
    allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
106
0
    allocInfo.pNext = nullptr;
107
0
    allocInfo.allocationSize = requirements.size;
108
0
    allocInfo.memoryTypeIndex = memoryTypeIndex;
109
110
0
    SkASSERT(fImageMemory == VK_NULL_HANDLE);
111
0
    VULKAN_CALL_RESULT(fSharedCtxt, result, AllocateMemory(fSharedCtxt->device(),
112
0
                                                           &allocInfo,
113
0
                                                           nullptr,
114
0
                                                           &fImageMemory));
115
0
    if (result != VK_SUCCESS) {
116
0
        return false;
117
0
    }
118
119
0
    void* mappedBuffer;
120
0
    VULKAN_CALL_RESULT(fSharedCtxt, result, MapMemory(fSharedCtxt->device(),
121
0
                                                      fImageMemory,
122
0
                                                      /*offset=*/0u,
123
0
                                                      requirements.size,
124
0
                                                      /*flags=*/0u,
125
0
                                                      &mappedBuffer));
126
0
    if (result != VK_SUCCESS) {
127
0
        return false;
128
0
    }
129
130
    // Write Y channel.
131
0
    VkImageSubresource subresource;
132
0
    subresource.aspectMask = VK_IMAGE_ASPECT_PLANE_0_BIT;
133
0
    subresource.mipLevel = 0;
134
0
    subresource.arrayLayer = 0;
135
136
0
    VkSubresourceLayout yLayout;
137
0
    VULKAN_CALL(fSharedCtxt->interface(),
138
0
                GetImageSubresourceLayout(fSharedCtxt->device(), fImage, &subresource, &yLayout));
139
0
    uint8_t* bufferData = reinterpret_cast<uint8_t*>(mappedBuffer) + yLayout.offset;
140
0
    for (size_t y = 0; y < height; ++y) {
141
0
        for (size_t x = 0; x < width; ++x) {
142
0
            bufferData[y * yLayout.rowPitch + x] = GetExpectedY(x, y, width, height);
143
0
        }
144
0
    }
145
146
    // Write UV channels.
147
0
    subresource.aspectMask = VK_IMAGE_ASPECT_PLANE_1_BIT;
148
0
    VkSubresourceLayout uvLayout;
149
0
    VULKAN_CALL(fSharedCtxt->interface(), GetImageSubresourceLayout(fSharedCtxt->device(),
150
0
                                                                    fImage,
151
0
                                                                    &subresource,
152
0
                                                                    &uvLayout));
153
0
    bufferData = reinterpret_cast<uint8_t*>(mappedBuffer) + uvLayout.offset;
154
0
    for (size_t y = 0; y < height / 2; ++y) {
155
0
        for (size_t x = 0; x < width / 2; ++x) {
156
0
            auto [u, v] = GetExpectedUV(2*x, 2*y, width, height);
157
0
            bufferData[y * uvLayout.rowPitch + x * 2] = u;
158
0
            bufferData[y * uvLayout.rowPitch + x * 2 + 1] = v;
159
0
        }
160
0
    }
161
162
0
    VkMappedMemoryRange flushRange;
163
0
    flushRange.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
164
0
    flushRange.pNext = nullptr;
165
0
    flushRange.memory = fImageMemory;
166
0
    flushRange.offset = 0;
167
0
    flushRange.size = VK_WHOLE_SIZE;
168
0
    VULKAN_CALL_RESULT(fSharedCtxt, result,  FlushMappedMemoryRanges(fSharedCtxt->device(),
169
0
                                                                     /*memoryRangeCount=*/1,
170
0
                                                                     &flushRange));
171
0
    if (result != VK_SUCCESS) {
172
0
        return false;
173
0
    }
174
0
    VULKAN_CALL(fSharedCtxt->interface(), UnmapMemory(fSharedCtxt->device(), fImageMemory));
175
176
    // Bind image memory.
177
0
    VULKAN_CALL_RESULT(fSharedCtxt, result, BindImageMemory(fSharedCtxt->device(),
178
0
                                                            fImage,
179
0
                                                            fImageMemory,
180
0
                                                            /*memoryOffset=*/0u));
181
0
    if (result != VK_SUCCESS) {
182
0
        return false;
183
0
    }
184
185
    // Wrap the image into SkImage.
186
0
    VkFormatProperties formatProperties;
187
0
    SkASSERT(fSharedCtxt->physDevice() != VK_NULL_HANDLE);
188
0
    VULKAN_CALL(fSharedCtxt->interface(),
189
0
                GetPhysicalDeviceFormatProperties(fSharedCtxt->physDevice(),
190
0
                                                  VK_FORMAT_G8_B8R8_2PLANE_420_UNORM,
191
0
                                                  &formatProperties));
192
0
    SkDEBUGCODE(auto linFlags = formatProperties.linearTilingFeatures;)
193
0
    SkASSERT((linFlags & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT) &&
194
0
             (linFlags & VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT) &&
195
0
             (linFlags & VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT) &&
196
0
             (linFlags & VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT));
197
198
0
    skgpu::VulkanYcbcrConversionInfo ycbcrInfo = {vkImageInfo.format,
199
0
                                                  /*externalFormat=*/0,
200
0
                                                  VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709,
201
0
                                                  VK_SAMPLER_YCBCR_RANGE_ITU_NARROW,
202
0
                                                  VK_CHROMA_LOCATION_COSITED_EVEN,
203
0
                                                  VK_CHROMA_LOCATION_COSITED_EVEN,
204
0
                                                  VK_FILTER_LINEAR,
205
0
                                                  false,
206
0
                                                  formatProperties.linearTilingFeatures};
207
0
    skgpu::VulkanAlloc alloc;
208
0
    alloc.fMemory = fImageMemory;
209
0
    alloc.fOffset = 0;
210
0
    alloc.fSize = requirements.size;
211
212
0
    skgpu::graphite::VulkanTextureInfo imageInfo = {
213
0
            static_cast<uint32_t>(vkImageInfo.samples),
214
0
            skgpu::Mipmapped::kNo,
215
0
            VK_IMAGE_CREATE_PROTECTED_BIT,
216
0
            vkImageInfo.format,
217
0
            vkImageInfo.tiling,
218
0
            vkImageInfo.usage,
219
0
            vkImageInfo.sharingMode,
220
0
            VK_IMAGE_ASPECT_PLANE_0_BIT | VK_IMAGE_ASPECT_PLANE_1_BIT,
221
0
            ycbcrInfo};
222
223
0
    fTexture = skgpu::graphite::BackendTextures::MakeVulkan({(int32_t)width, (int32_t)height},
224
0
                                                            imageInfo,
225
0
                                                            VK_IMAGE_LAYOUT_UNDEFINED,
226
0
                                                            /*queueFamilyIndex=*/0,
227
0
                                                            fImage,
228
0
                                                            alloc);
229
0
    return true;
230
0
}
Unexecuted instantiation: VkYcbcrSamplerHelper::createBackendTexture(unsigned int, unsigned int)
Unexecuted instantiation: VkYcbcrSamplerHelper::createBackendTexture(unsigned int, unsigned int)
231
#endif // SK_GRAPHITE
232
233
0
bool VkYcbcrSamplerHelper::createGrBackendTexture(uint32_t width, uint32_t height) {
234
0
    GrVkGpu* vkGpu = this->vkGpu();
235
0
    VkResult result;
236
237
    // Create YCbCr image.
238
0
    VkImageCreateInfo vkImageInfo;
239
0
    populate_ycbcr_image_info(&vkImageInfo, width, height);
240
0
    SkASSERT(fImage == VK_NULL_HANDLE);
241
242
0
    GR_VK_CALL_RESULT(vkGpu, result, CreateImage(vkGpu->device(), &vkImageInfo, nullptr, &fImage));
243
0
    if (result != VK_SUCCESS) {
244
0
        return false;
245
0
    }
246
247
0
    VkMemoryRequirements requirements;
248
0
    GR_VK_CALL(vkGpu->vkInterface(), GetImageMemoryRequirements(vkGpu->device(),
249
0
                                                                fImage,
250
0
                                                                &requirements));
251
252
0
    uint32_t memoryTypeIndex = 0;
253
0
    VkPhysicalDeviceMemoryProperties phyDevMemProps;
254
0
    GR_VK_CALL(vkGpu->vkInterface(), GetPhysicalDeviceMemoryProperties(vkGpu->physicalDevice(),
255
0
                                                                       &phyDevMemProps));
256
0
    if (!find_memory_type_index(phyDevMemProps, requirements, &memoryTypeIndex)) {
257
0
        return false;
258
0
    }
259
260
0
    VkMemoryAllocateInfo allocInfo = {};
261
0
    allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
262
0
    allocInfo.allocationSize = requirements.size;
263
0
    allocInfo.memoryTypeIndex = memoryTypeIndex;
264
265
0
    SkASSERT(fImageMemory == VK_NULL_HANDLE);
266
0
    GR_VK_CALL_RESULT(vkGpu, result, AllocateMemory(vkGpu->device(), &allocInfo,
267
0
                                                    nullptr, &fImageMemory));
268
0
    if (result != VK_SUCCESS) {
269
0
        return false;
270
0
    }
271
272
0
    void* mappedBuffer;
273
0
    GR_VK_CALL_RESULT(vkGpu, result, MapMemory(vkGpu->device(), fImageMemory, 0u,
274
0
                                               requirements.size, 0u, &mappedBuffer));
275
0
    if (result != VK_SUCCESS) {
276
0
        return false;
277
0
    }
278
279
    // Write Y channel.
280
0
    VkImageSubresource subresource;
281
0
    subresource.aspectMask = VK_IMAGE_ASPECT_PLANE_0_BIT;
282
0
    subresource.mipLevel = 0;
283
0
    subresource.arrayLayer = 0;
284
285
0
    VkSubresourceLayout yLayout;
286
0
    GR_VK_CALL(vkGpu->vkInterface(), GetImageSubresourceLayout(vkGpu->device(), fImage,
287
0
                                                               &subresource, &yLayout));
288
0
    uint8_t* bufferData = reinterpret_cast<uint8_t*>(mappedBuffer) + yLayout.offset;
289
0
    for (size_t y = 0; y < height; ++y) {
290
0
        for (size_t x = 0; x < width; ++x) {
291
0
            bufferData[y * yLayout.rowPitch + x] = GetExpectedY(x, y, width, height);
292
0
        }
293
0
    }
294
295
    // Write UV channels.
296
0
    subresource.aspectMask = VK_IMAGE_ASPECT_PLANE_1_BIT;
297
0
    VkSubresourceLayout uvLayout;
298
0
    GR_VK_CALL(vkGpu->vkInterface(), GetImageSubresourceLayout(vkGpu->device(), fImage,
299
0
                                                               &subresource, &uvLayout));
300
0
    bufferData = reinterpret_cast<uint8_t*>(mappedBuffer) + uvLayout.offset;
301
0
    for (size_t y = 0; y < height / 2; ++y) {
302
0
        for (size_t x = 0; x < width / 2; ++x) {
303
0
            auto [u, v] = GetExpectedUV(2*x, 2*y, width, height);
304
0
            bufferData[y * uvLayout.rowPitch + x * 2] = u;
305
0
            bufferData[y * uvLayout.rowPitch + x * 2 + 1] = v;
306
0
        }
307
0
    }
308
309
0
    VkMappedMemoryRange flushRange;
310
0
    flushRange.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
311
0
    flushRange.pNext = nullptr;
312
0
    flushRange.memory = fImageMemory;
313
0
    flushRange.offset = 0;
314
0
    flushRange.size = VK_WHOLE_SIZE;
315
0
    GR_VK_CALL_RESULT(vkGpu, result, FlushMappedMemoryRanges(vkGpu->device(), 1, &flushRange));
316
0
    if (result != VK_SUCCESS) {
317
0
        return false;
318
0
    }
319
0
    GR_VK_CALL(vkGpu->vkInterface(), UnmapMemory(vkGpu->device(), fImageMemory));
320
321
    // Bind image memory.
322
0
    GR_VK_CALL_RESULT(vkGpu, result, BindImageMemory(vkGpu->device(), fImage, fImageMemory, 0u));
323
0
    if (result != VK_SUCCESS) {
324
0
        return false;
325
0
    }
326
327
    // Wrap the image into SkImage.
328
0
    VkFormatProperties formatProperties;
329
0
    GR_VK_CALL(vkGpu->vkInterface(),
330
0
               GetPhysicalDeviceFormatProperties(vkGpu->physicalDevice(),
331
0
                                                 VK_FORMAT_G8_B8R8_2PLANE_420_UNORM,
332
0
                                                 &formatProperties));
333
0
    SkDEBUGCODE(auto linFlags = formatProperties.linearTilingFeatures;)
334
0
    SkASSERT((linFlags & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT) &&
335
0
             (linFlags & VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT) &&
336
0
             (linFlags & VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT) &&
337
0
             (linFlags & VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT));
338
339
0
    skgpu::VulkanYcbcrConversionInfo ycbcrInfo = {vkImageInfo.format,
340
0
                                                  /*externalFormat=*/0,
341
0
                                                  VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709,
342
0
                                                  VK_SAMPLER_YCBCR_RANGE_ITU_NARROW,
343
0
                                                  VK_CHROMA_LOCATION_COSITED_EVEN,
344
0
                                                  VK_CHROMA_LOCATION_COSITED_EVEN,
345
0
                                                  VK_FILTER_LINEAR,
346
0
                                                  false,
347
0
                                                  formatProperties.linearTilingFeatures,
348
0
                                                  /*fComponents=*/{}};
349
0
    skgpu::VulkanAlloc alloc;
350
0
    alloc.fMemory = fImageMemory;
351
0
    alloc.fOffset = 0;
352
0
    alloc.fSize = requirements.size;
353
354
0
    GrVkImageInfo imageInfo = {fImage,
355
0
                               alloc,
356
0
                               VK_IMAGE_TILING_LINEAR,
357
0
                               VK_IMAGE_LAYOUT_UNDEFINED,
358
0
                               vkImageInfo.format,
359
0
                               vkImageInfo.usage,
360
0
                               1 /* sample count */,
361
0
                               1 /* levelCount */,
362
0
                               VK_QUEUE_FAMILY_IGNORED,
363
0
                               GrProtected::kNo,
364
0
                               ycbcrInfo};
365
366
0
    fGrTexture = GrBackendTextures::MakeVk(width, height, imageInfo);
367
0
    return true;
368
0
}
Unexecuted instantiation: VkYcbcrSamplerHelper::createGrBackendTexture(unsigned int, unsigned int)
Unexecuted instantiation: VkYcbcrSamplerHelper::createGrBackendTexture(unsigned int, unsigned int)
369
370
0
GrVkGpu* VkYcbcrSamplerHelper::vkGpu() {
371
0
    return (GrVkGpu*) fDContext->priv().getGpu();
372
0
}
373
374
0
VkYcbcrSamplerHelper::VkYcbcrSamplerHelper(GrDirectContext* dContext) : fDContext(dContext) {
375
0
    SkASSERT_RELEASE(dContext->backend() == GrBackendApi::kVulkan);
376
0
#if defined(SK_GRAPHITE)
377
0
    fSharedCtxt = nullptr;
378
0
#endif
379
0
}
380
381
0
VkYcbcrSamplerHelper::~VkYcbcrSamplerHelper() {
382
0
#ifdef SK_GRAPHITE
383
0
    if (fSharedCtxt) {
384
0
        if (fImage != VK_NULL_HANDLE) {
385
0
            VULKAN_CALL(fSharedCtxt->interface(),
386
0
                        DestroyImage(fSharedCtxt->device(), fImage, nullptr));
387
0
            fImage = VK_NULL_HANDLE;
388
0
        }
389
0
        if (fImageMemory != VK_NULL_HANDLE) {
390
0
            VULKAN_CALL(fSharedCtxt->interface(),
391
0
                        FreeMemory(fSharedCtxt->device(), fImageMemory, nullptr));
392
0
            fImageMemory = VK_NULL_HANDLE;
393
0
        }
394
0
    } else
395
0
#endif // SK_GRAPHITE
396
0
    {
397
0
        GrVkGpu* vkGpu = this->vkGpu();
398
399
0
        if (fImage != VK_NULL_HANDLE) {
400
0
            GR_VK_CALL(vkGpu->vkInterface(), DestroyImage(vkGpu->device(), fImage, nullptr));
401
0
            fImage = VK_NULL_HANDLE;
402
0
        }
403
0
        if (fImageMemory != VK_NULL_HANDLE) {
404
0
            GR_VK_CALL(vkGpu->vkInterface(), FreeMemory(vkGpu->device(), fImageMemory, nullptr));
405
0
            fImageMemory = VK_NULL_HANDLE;
406
0
        }
407
0
    }
408
0
}
409
410
0
bool VkYcbcrSamplerHelper::isYCbCrSupported() {
411
0
    VkFormatProperties formatProperties;
412
0
#ifdef SK_GRAPHITE
413
0
    if (fSharedCtxt) {
414
0
        if (!fSharedCtxt->vulkanCaps().supportsYcbcrConversion()) {
415
0
            return false;
416
0
        }
417
418
0
        SkASSERT(fSharedCtxt->physDevice() != VK_NULL_HANDLE);
419
0
        VULKAN_CALL(fSharedCtxt->interface(),
420
0
                    GetPhysicalDeviceFormatProperties(fSharedCtxt->physDevice(),
421
0
                                                      VK_FORMAT_G8_B8R8_2PLANE_420_UNORM,
422
0
                                                      &formatProperties));
423
0
    } else
424
0
#endif
425
0
    {
426
0
        GrVkGpu* vkGpu = this->vkGpu();
427
0
        if (!vkGpu->vkCaps().supportsYcbcrConversion()) {
428
0
            return false;
429
0
        }
430
431
0
        GR_VK_CALL(vkGpu->vkInterface(),
432
0
                GetPhysicalDeviceFormatProperties(vkGpu->physicalDevice(),
433
0
                                                    VK_FORMAT_G8_B8R8_2PLANE_420_UNORM,
434
0
                                                    &formatProperties));
435
0
    }
436
437
    // The createBackendTexture call (which is the point of this helper class) requires linear
438
    // support for VK_FORMAT_G8_B8R8_2PLANE_420_UNORM including sampling and cosited chroma.
439
    // Verify that the image format is supported.
440
0
    auto linFlags = formatProperties.linearTilingFeatures;
441
0
    if (!(linFlags & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT) ||
442
0
        !(linFlags & VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT) ||
443
0
        !(linFlags & VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT) ||
444
0
        !(linFlags & VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT)) {
445
        // VK_FORMAT_G8_B8R8_2PLANE_420_UNORM is not supported
446
0
        return false;
447
0
    }
448
0
    return true;
449
0
}
Unexecuted instantiation: VkYcbcrSamplerHelper::isYCbCrSupported()
Unexecuted instantiation: VkYcbcrSamplerHelper::isYCbCrSupported()
450
#endif // SK_VULKAN