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