1 /*
2 * Copyright 2016 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/SkAlphaType.h"
9 #include "include/core/SkColorType.h"
10 #include "include/core/SkImageInfo.h"
11 #include "include/core/SkPoint.h"
12 #include "include/core/SkRect.h"
13 #include "include/core/SkTypes.h"
14 #include "include/gpu/GpuTypes.h"
15 #include "include/gpu/ganesh/GrBackendSurface.h"
16 #include "include/gpu/ganesh/GrDirectContext.h"
17 #include "include/gpu/ganesh/GrTypes.h"
18 #include "include/private/base/SkTemplates.h"
19 #include "src/core/SkMemset.h"
20 #include "src/gpu/ganesh/GrDirectContextPriv.h"
21 #include "src/gpu/ganesh/GrImageInfo.h"
22 #include "src/gpu/ganesh/GrPixmap.h"
23 #include "src/gpu/ganesh/GrSurfaceProxyView.h"
24 #include "src/gpu/ganesh/SurfaceContext.h"
25 #include "src/gpu/ganesh/SurfaceFillContext.h"
26 #include "tests/CtsEnforcement.h"
27 #include "tests/Test.h"
28 #include "tools/gpu/ProxyUtils.h"
29
30 #include <cstddef>
31 #include <cstdint>
32 #include <initializer_list>
33 #include <memory>
34 #include <utility>
35
36 using namespace skia_private;
37
38 struct GrContextOptions;
39
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(CopySurface,reporter,ctxInfo,CtsEnforcement::kApiLevel_T)40 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(CopySurface,
41 reporter,
42 ctxInfo,
43 CtsEnforcement::kApiLevel_T) {
44 auto dContext = ctxInfo.directContext();
45
46 static const int kW = 10;
47 static const int kH = 10;
48 static const size_t kRowBytes = sizeof(uint32_t) * kW;
49
50 AutoTMalloc<uint32_t> srcPixels(kW * kH);
51 for (int i = 0; i < kW * kH; ++i) {
52 srcPixels.get()[i] = i;
53 }
54
55 AutoTMalloc<uint32_t> dstPixels(kW * kH);
56 for (int i = 0; i < kW * kH; ++i) {
57 dstPixels.get()[i] = ~i;
58 }
59
60 static const SkIRect kSrcRects[] {
61 { 0, 0, kW , kH },
62 {-1, -1, kW+1, kH+1},
63 { 1, 1, kW-1, kH-1},
64 { 5, 5, 6 , 6 },
65 };
66
67 static const SkIPoint kDstPoints[] {
68 { 0 , 0 },
69 { 1 , 1 },
70 { kW/2, kH/4},
71 { kW-1, kH-1},
72 { kW , kH },
73 { kW+1, kH+2},
74 {-1 , -1 },
75 };
76
77 static const SkImageInfo kImageInfos[] {
78 SkImageInfo::Make(kW, kH, kRGBA_8888_SkColorType, kPremul_SkAlphaType),
79 SkImageInfo::Make(kW, kH, kBGRA_8888_SkColorType, kPremul_SkAlphaType)
80 };
81
82 AutoTMalloc<uint32_t> read(kW * kH);
83
84 for (auto sOrigin : {kBottomLeft_GrSurfaceOrigin, kTopLeft_GrSurfaceOrigin}) {
85 for (auto dOrigin : {kBottomLeft_GrSurfaceOrigin, kTopLeft_GrSurfaceOrigin}) {
86 for (auto sRenderable : {GrRenderable::kYes, GrRenderable::kNo}) {
87 for (auto dRenderable : {GrRenderable::kYes, GrRenderable::kNo}) {
88 for (const SkIRect& srcRect : kSrcRects) {
89 for (const SkIPoint& dstPoint : kDstPoints) {
90 for (const SkImageInfo& ii: kImageInfos) {
91 GrCPixmap srcPM(ii, srcPixels.get(), kRowBytes);
92 GrPixmap dstPM(ii, dstPixels.get(), kRowBytes);
93 auto srcView = sk_gpu_test::MakeTextureProxyViewFromData(
94 dContext, sRenderable, sOrigin, srcPM);
95 auto dstView = sk_gpu_test::MakeTextureProxyViewFromData(
96 dContext, dRenderable, dOrigin, dstPM);
97
98 // Should always work if the color type is RGBA, but may not work
99 // for BGRA
100 if (ii.colorType() == kRGBA_8888_SkColorType) {
101 if (!srcView || !dstView) {
102 ERRORF(reporter,
103 "Could not create surfaces for copy surface test.");
104 continue;
105 }
106 } else {
107 if (!dContext->defaultBackendFormat(
108 kBGRA_8888_SkColorType, GrRenderable::kNo).isValid()) {
109 continue;
110 }
111 if (!srcView || !dstView) {
112 ERRORF(reporter,
113 "Could not create surfaces for copy surface test.");
114 continue;
115 }
116 }
117
118 auto dstContext = dContext->priv().makeSC(std::move(dstView),
119 ii.colorInfo());
120
121 bool result = false;
122 if (sOrigin == dOrigin) {
123 result = dstContext->testCopy(srcView.refProxy(),
124 srcRect,
125 dstPoint);
126 } else if (dRenderable == GrRenderable::kYes) {
127 SkASSERT(dstContext->asFillContext());
128 result = dstContext->asFillContext()->blitTexture(
129 std::move(srcView), srcRect, dstPoint);
130 }
131
132 bool expectedResult = true;
133 SkIPoint dstOffset = { dstPoint.fX - srcRect.fLeft,
134 dstPoint.fY - srcRect.fTop };
135 SkIRect copiedDstRect = SkIRect::MakeXYWH(dstPoint.fX,
136 dstPoint.fY,
137 srcRect.width(),
138 srcRect.height());
139
140 SkIRect copiedSrcRect;
141 if (!copiedSrcRect.intersect(srcRect, SkIRect::MakeWH(kW, kH))) {
142 expectedResult = false;
143 } else {
144 // If the src rect was clipped, apply same clipping to each side
145 // of copied dst rect.
146 copiedDstRect.fLeft += copiedSrcRect.fLeft - srcRect.fLeft;
147 copiedDstRect.fTop += copiedSrcRect.fTop - srcRect.fTop;
148 copiedDstRect.fRight -= copiedSrcRect.fRight - srcRect.fRight;
149 copiedDstRect.fBottom -= copiedSrcRect.fBottom -
150 srcRect.fBottom;
151 }
152 if (copiedDstRect.isEmpty() ||
153 !copiedDstRect.intersect(SkIRect::MakeWH(kW, kH))) {
154 expectedResult = false;
155 }
156 if (sOrigin != dOrigin && dRenderable == GrRenderable::kNo) {
157 expectedResult = false;
158 }
159
160 // To make the copied src rect correct we would apply any dst
161 // clipping back to the src rect, but we don't use it again so
162 // don't bother.
163 if (expectedResult != result) {
164 ERRORF(reporter, "Expected return value %d from copySurface, "
165 "got %d.", expectedResult, result);
166 continue;
167 }
168
169 if (!expectedResult || !result) {
170 continue;
171 }
172
173 SkOpts::memset32(read.get(), 0, kW * kH);
174 GrPixmap readPM(ii, read.get(), kRowBytes);
175 if (!dstContext->readPixels(dContext, readPM, {0, 0})) {
176 ERRORF(reporter, "Error calling readPixels");
177 continue;
178 }
179
180 bool abort = false;
181 // Validate that pixels inside copiedDstRect received the correct
182 // value from src and that those outside were not modified.
183 for (int y = 0; y < kH && !abort; ++y) {
184 for (int x = 0; x < kW; ++x) {
185 uint32_t r = read.get()[y * kW + x];
186 if (copiedDstRect.contains(x, y)) {
187 int sx = x - dstOffset.fX;
188 int sy = y - dstOffset.fY;
189 uint32_t s = srcPixels.get()[sy * kW + sx];
190 if (s != r) {
191 ERRORF(reporter, "Expected dst %d,%d to contain "
192 "0x%08x copied from src location %d,%d. Got "
193 "0x%08x", x, y, s, sx, sy, r);
194 abort = true;
195 break;
196 }
197 } else {
198 uint32_t d = dstPixels.get()[y * kW + x];
199 if (d != r) {
200 ERRORF(reporter, "Expected dst %d,%d to be "
201 "unmodified (0x%08x). Got 0x%08x",
202 x, y, d, r);
203 abort = true;
204 break;
205 }
206 }
207 }
208 }
209 }
210 }
211 }
212 }
213 }
214 }
215 }
216 }
217