Flutter Engine
The Flutter Engine
VkYcbcrSamplerTest.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2019 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
9
10#if defined(SK_GANESH) && defined(SK_VULKAN)
22#include "include/gpu/GrTypes.h"
27#include "tests/Test.h"
29
30#include <vulkan/vulkan_core.h>
31
32#include <cmath>
33#include <cstddef>
34#include <cstdint>
35#include <vector>
36
37class SkImage;
38struct GrContextOptions;
39const size_t kImageWidth = 8;
40const size_t kImageHeight = 8;
41
42static int round_and_clamp(float x) {
43 int r = static_cast<int>(round(x));
44 if (r > 255) return 255;
45 if (r < 0) return 0;
46 return r;
47}
48
49DEF_GANESH_TEST_FOR_VULKAN_CONTEXT(VkYCbcrSampler_DrawImageWithYcbcrSampler,
51 ctxInfo,
53 GrDirectContext* dContext = ctxInfo.directContext();
54
55 VkYcbcrSamplerHelper ycbcrHelper(dContext);
56 if (!ycbcrHelper.isYCbCrSupported()) {
57 return;
58 }
59
60 if (!ycbcrHelper.createGrBackendTexture(kImageWidth, kImageHeight)) {
61 ERRORF(reporter, "Failed to create I420 backend texture");
62 return;
63 }
64
66 ycbcrHelper.grBackendTexture(),
70 nullptr);
71 if (!srcImage) {
72 ERRORF(reporter, "Failed to create I420 image");
73 return;
74 }
75
77 dContext,
80 if (!surface) {
81 ERRORF(reporter, "Failed to create target SkSurface");
82 return;
83 }
84 surface->getCanvas()->drawImage(srcImage, 0, 0);
85 dContext->flushAndSubmit(surface.get());
86
87 std::vector<uint8_t> readbackData(kImageWidth * kImageHeight * 4);
90 readbackData.data(), kImageWidth * 4, 0, 0)) {
91 ERRORF(reporter, "Readback failed");
92 return;
93 }
94
95 // Allow resulting color to be off by 1 in each channel as some Vulkan implementations do not
96 // round YCbCr sampler result properly.
97 const int kColorTolerance = 1;
98
99 // Verify results only for pixels with even coordinates, since others use
100 // interpolated U & V channels.
101 for (size_t y = 0; y < kImageHeight; y += 2) {
102 for (size_t x = 0; x < kImageWidth; x += 2) {
103 auto y2 = VkYcbcrSamplerHelper::GetExpectedY(x, y, kImageWidth, kImageHeight);
104 auto [u, v] = VkYcbcrSamplerHelper::GetExpectedUV(x, y, kImageWidth, kImageHeight);
105
106 // createI420Image() initializes the image with VK_SAMPLER_YCBCR_RANGE_ITU_NARROW.
107 float yChannel = (static_cast<float>(y2) - 16.0) / 219.0;
108 float uChannel = (static_cast<float>(u) - 128.0) / 224.0;
109 float vChannel = (static_cast<float>(v) - 128.0) / 224.0;
110
111 // BR.709 conversion as specified in
112 // https://www.khronos.org/registry/DataFormat/specs/1.2/dataformat.1.2.html#MODEL_YUV
113 int expectedR = round_and_clamp((yChannel + 1.5748f * vChannel) * 255.0);
114 int expectedG = round_and_clamp((yChannel - 0.13397432f / 0.7152f * uChannel -
115 0.33480248f / 0.7152f * vChannel) *
116 255.0);
117 int expectedB = round_and_clamp((yChannel + 1.8556f * uChannel) * 255.0);
118
119 int r = readbackData[(y * kImageWidth + x) * 4];
120 if (abs(r - expectedR) > kColorTolerance) {
121 ERRORF(reporter, "R should be %d, but is %d at (%zu, %zu)", expectedR, r, x, y);
122 }
123
124 int g = readbackData[(y * kImageWidth + x) * 4 + 1];
125 if (abs(g - expectedG) > kColorTolerance) {
126 ERRORF(reporter, "G should be %d, but is %d at (%zu, %zu)", expectedG, g, x, y);
127 }
128
129 int b = readbackData[(y * kImageWidth + x) * 4 + 2];
130 if (abs(b - expectedB) > kColorTolerance) {
131 ERRORF(reporter, "B should be %d, but is %d at (%zu, %zu)", expectedB, b, x, y);
132 }
133 }
134 }
135}
136
137// Verifies that it's not possible to allocate Ycbcr texture directly.
138DEF_GANESH_TEST_FOR_VULKAN_CONTEXT(VkYCbcrSampler_NoYcbcrSurface,
139 reporter,
140 ctxInfo,
142 GrDirectContext* dContext = ctxInfo.directContext();
143
144 VkYcbcrSamplerHelper ycbcrHelper(dContext);
145 if (!ycbcrHelper.isYCbCrSupported()) {
146 return;
147 }
148
156 if (texture.isValid()) {
158 "GrDirectContext::createBackendTexture() didn't fail as expected for Ycbcr format.");
159 }
160}
161
162#endif // defined(SK_GANESH) && defined(SK_VULKAN)
reporter
Definition: FontMgrTest.cpp:39
static constexpr int kImageWidth
Definition: GrMeshTest.cpp:89
static constexpr int kImageHeight
Definition: GrMeshTest.cpp:90
static void round(SkPoint *p)
@ kTopLeft_GrSurfaceOrigin
Definition: GrTypes.h:148
@ kOpaque_SkAlphaType
pixel is opaque
Definition: SkAlphaType.h:28
@ kPremul_SkAlphaType
pixel components are premultiplied by alpha
Definition: SkAlphaType.h:29
@ kRGBA_8888_SkColorType
pixel with 8 bits for red, green, blue, alpha; in 32-bit word
Definition: SkColorType.h:24
@ kRGB_888x_SkColorType
pixel with 8 bits each for red, green, blue; in 32-bit word
Definition: SkColorType.h:25
#define DEF_GANESH_TEST_FOR_VULKAN_CONTEXT(name, reporter, context_info, ctsEnforcement)
Definition: Test.h:458
#define ERRORF(r,...)
Definition: Test.h:293
void flushAndSubmit(GrSyncCpu sync=GrSyncCpu::kNo)
GrBackendTexture createBackendTexture(int width, int height, const GrBackendFormat &, skgpu::Mipmapped, GrRenderable, GrProtected=GrProtected::kNo, std::string_view label={})
VkSurfaceKHR surface
Definition: main.cc:49
static bool b
FlTexture * texture
double y
double x
SK_API GrBackendFormat MakeVk(VkFormat format, bool willUseDRMFormatModifiers=false)
SK_API sk_sp< SkImage > BorrowTextureFrom(GrRecordingContext *context, const GrBackendTexture &backendTexture, GrSurfaceOrigin origin, SkColorType colorType, SkAlphaType alphaType, sk_sp< SkColorSpace > colorSpace, TextureReleaseProc textureReleaseProc=nullptr, ReleaseContext releaseContext=nullptr)
SK_API sk_sp< SkSurface > RenderTarget(GrRecordingContext *context, skgpu::Budgeted budgeted, const SkImageInfo &imageInfo, int sampleCount, GrSurfaceOrigin surfaceOrigin, const SkSurfaceProps *surfaceProps, bool shouldCreateWithMips=false, bool isProtected=false)
SIN Vec< N, float > abs(const Vec< N, float > &x)
Definition: SkVx.h:707
static SkImageInfo Make(int width, int height, SkColorType ct, SkAlphaType at)
@ VK_FORMAT_G8_B8R8_2PLANE_420_UNORM
Definition: vulkan_core.h:1647