blob: 6dc7507589592a48608e5843414d00cec90eb689 [file] [log] [blame]
Sergey Ulanov2739fd22019-08-11 22:46:33 -07001/*
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
8#include "include/core/SkTypes.h"
9
10#if SK_SUPPORT_GPU && defined(SK_VULKAN)
11
Brian Osman01e6d172020-03-30 15:57:14 -040012#include "include/core/SkCanvas.h"
Sergey Ulanov2739fd22019-08-11 22:46:33 -070013#include "include/core/SkImage.h"
14#include "include/core/SkSurface.h"
Robert Phillips0c5bb2f2020-07-17 15:40:13 -040015#include "include/gpu/GrDirectContext.h"
Sergey Ulanov2739fd22019-08-11 22:46:33 -070016#include "tests/Test.h"
Robert Phillips85aa4282020-06-11 10:54:43 -040017#include "tools/gpu/vk/VkTestHelper.h"
Robert Phillipsae413d82020-06-10 11:04:51 -040018#include "tools/gpu/vk/VkYcbcrSamplerHelper.h"
Sergey Ulanov2739fd22019-08-11 22:46:33 -070019
20const size_t kImageWidth = 8;
21const size_t kImageHeight = 8;
22
Sergey Ulanov2739fd22019-08-11 22:46:33 -070023static int round_and_clamp(float x) {
24 int r = static_cast<int>(round(x));
25 if (r > 255) return 255;
26 if (r < 0) return 0;
27 return r;
28}
29
30DEF_GPUTEST(VkYCbcrSampler_DrawImageWithYcbcrSampler, reporter, options) {
Robert Phillips85aa4282020-06-11 10:54:43 -040031 VkTestHelper testHelper(false);
32 if (!testHelper.init()) {
33 ERRORF(reporter, "VkTestHelper initialization failed.");
Sergey Ulanov2739fd22019-08-11 22:46:33 -070034 return;
35 }
36
Robert Phillips2a4acf32020-07-06 15:50:15 -040037 VkYcbcrSamplerHelper ycbcrHelper(testHelper.directContext());
Robert Phillips85aa4282020-06-11 10:54:43 -040038 if (!ycbcrHelper.isYCbCrSupported()) {
Robert Phillipsae413d82020-06-10 11:04:51 -040039 return;
40 }
41
Robert Phillips5f0cda42020-06-15 14:26:58 -040042 if (!ycbcrHelper.createBackendTexture(kImageWidth, kImageHeight)) {
43 ERRORF(reporter, "Failed to create I420 backend texture");
44 return;
45 }
46
Robert Phillips2a4acf32020-07-06 15:50:15 -040047 sk_sp<SkImage> srcImage = SkImage::MakeFromTexture(testHelper.directContext(),
Robert Phillips5f0cda42020-06-15 14:26:58 -040048 ycbcrHelper.backendTexture(),
49 kTopLeft_GrSurfaceOrigin,
50 kRGB_888x_SkColorType,
51 kPremul_SkAlphaType,
52 nullptr);
Sergey Ulanov2739fd22019-08-11 22:46:33 -070053 if (!srcImage) {
Robert Phillipsae413d82020-06-10 11:04:51 -040054 ERRORF(reporter, "Failed to create I420 image");
Sergey Ulanov2739fd22019-08-11 22:46:33 -070055 return;
56 }
57
58 sk_sp<SkSurface> surface = SkSurface::MakeRenderTarget(
Robert Phillips2a4acf32020-07-06 15:50:15 -040059 testHelper.directContext(), SkBudgeted::kNo,
Sergey Ulanov2739fd22019-08-11 22:46:33 -070060 SkImageInfo::Make(kImageWidth, kImageHeight, kN32_SkColorType, kPremul_SkAlphaType));
61 if (!surface) {
62 ERRORF(reporter, "Failed to create target SkSurface");
63 return;
64 }
65 surface->getCanvas()->drawImage(srcImage, 0, 0);
Greg Daniel0a2464f2020-05-14 15:45:44 -040066 surface->flushAndSubmit();
Sergey Ulanov2739fd22019-08-11 22:46:33 -070067
68 std::vector<uint8_t> readbackData(kImageWidth * kImageHeight * 4);
69 if (!surface->readPixels(SkImageInfo::Make(kImageWidth, kImageHeight, kRGBA_8888_SkColorType,
70 kOpaque_SkAlphaType),
71 readbackData.data(), kImageWidth * 4, 0, 0)) {
72 ERRORF(reporter, "Readback failed");
73 return;
74 }
75
76 // Allow resulting color to be off by 1 in each channel as some Vulkan implementations do not
77 // round YCbCr sampler result properly.
78 const int kColorTolerance = 1;
79
80 // Verify results only for pixels with even coordinates, since others use
81 // interpolated U & V channels.
82 for (size_t y = 0; y < kImageHeight; y += 2) {
83 for (size_t x = 0; x < kImageWidth; x += 2) {
Robert Phillipsae413d82020-06-10 11:04:51 -040084 auto y2 = VkYcbcrSamplerHelper::GetExpectedY(x, y, kImageWidth, kImageHeight);
85 auto [u, v] = VkYcbcrSamplerHelper::GetExpectedUV(x, y, kImageWidth, kImageHeight);
86
Sergey Ulanov2739fd22019-08-11 22:46:33 -070087 // createI420Image() initializes the image with VK_SAMPLER_YCBCR_RANGE_ITU_NARROW.
Robert Phillipsae413d82020-06-10 11:04:51 -040088 float yChannel = (static_cast<float>(y2) - 16.0) / 219.0;
89 float uChannel = (static_cast<float>(u) - 128.0) / 224.0;
90 float vChannel = (static_cast<float>(v) - 128.0) / 224.0;
Sergey Ulanov2739fd22019-08-11 22:46:33 -070091
92 // BR.709 conversion as specified in
93 // https://www.khronos.org/registry/DataFormat/specs/1.2/dataformat.1.2.html#MODEL_YUV
94 int expectedR = round_and_clamp((yChannel + 1.5748f * vChannel) * 255.0);
95 int expectedG = round_and_clamp((yChannel - 0.13397432f / 0.7152f * uChannel -
96 0.33480248f / 0.7152f * vChannel) *
97 255.0);
98 int expectedB = round_and_clamp((yChannel + 1.8556f * uChannel) * 255.0);
99
100 int r = readbackData[(y * kImageWidth + x) * 4];
101 if (abs(r - expectedR) > kColorTolerance) {
102 ERRORF(reporter, "R should be %d, but is %d at (%d, %d)", expectedR, r, x, y);
103 }
104
105 int g = readbackData[(y * kImageWidth + x) * 4 + 1];
106 if (abs(g - expectedG) > kColorTolerance) {
107 ERRORF(reporter, "G should be %d, but is %d at (%d, %d)", expectedG, g, x, y);
108 }
109
110 int b = readbackData[(y * kImageWidth + x) * 4 + 2];
111 if (abs(b - expectedB) > kColorTolerance) {
112 ERRORF(reporter, "B should be %d, but is %d at (%d, %d)", expectedB, b, x, y);
113 }
114 }
115 }
116}
117
118// Verifies that it's not possible to allocate Ycbcr texture directly.
119DEF_GPUTEST(VkYCbcrSampler_NoYcbcrSurface, reporter, options) {
Robert Phillips85aa4282020-06-11 10:54:43 -0400120 VkTestHelper testHelper(false);
121 if (!testHelper.init()) {
122 ERRORF(reporter, "VkTestHelper initialization failed.");
Robert Phillipsae413d82020-06-10 11:04:51 -0400123 return;
124 }
125
Robert Phillips2a4acf32020-07-06 15:50:15 -0400126 VkYcbcrSamplerHelper ycbcrHelper(testHelper.directContext());
Robert Phillips85aa4282020-06-11 10:54:43 -0400127 if (!ycbcrHelper.isYCbCrSupported()) {
Sergey Ulanov2739fd22019-08-11 22:46:33 -0700128 return;
129 }
130
Robert Phillips2a4acf32020-07-06 15:50:15 -0400131 GrBackendTexture texture = testHelper.directContext()->createBackendTexture(
Sergey Ulanov2739fd22019-08-11 22:46:33 -0700132 kImageWidth, kImageHeight, GrBackendFormat::MakeVk(VK_FORMAT_G8_B8R8_2PLANE_420_UNORM),
Brian Salomon7e67dca2020-07-21 09:27:25 -0400133 GrMipmapped::kNo, GrRenderable::kNo, GrProtected::kNo);
Sergey Ulanov2739fd22019-08-11 22:46:33 -0700134 if (texture.isValid()) {
135 ERRORF(reporter,
136 "GrContext::createBackendTexture() didn't fail as expected for Ycbcr format.");
137 }
138}
139
140#endif // SK_SUPPORT_GPU && defined(SK_VULKAN)